summaryrefslogtreecommitdiffstats
path: root/cpukit/libi2c
diff options
context:
space:
mode:
authorTill Straumann <strauman@slac.stanford.edu>2007-11-21 06:20:49 +0000
committerTill Straumann <strauman@slac.stanford.edu>2007-11-21 06:20:49 +0000
commitd2ff24c22d65f24163e9063c78896459384c5627 (patch)
treedfffba11bf10034e1bd9f9a79707b1bc33fb0d48 /cpukit/libi2c
parent2007-11-20 Till Straumann <strauman@slac.stanford.edu> (diff)
downloadrtems-d2ff24c22d65f24163e9063c78896459384c5627.tar.bz2
2007-11-17 Till Straumann <strauman@slac.stanford.edu>
* libi2c/libi2c.c, libi2c/libi2c.h, libi2c/README_libi2c: Added checks so that use of 'stdio' is avoided (falling back to 'printk') before the system is up. Publish driver entry points so that the libi2c driver could be added to the applications 'device driver table'. This is not fully implemented yet, though, since in addition to initializing libi2c the low-level i2c bus drivers as well as high-level i2c device drivers need to be registered with the library. Updated README_libi2c accordingly.
Diffstat (limited to 'cpukit/libi2c')
-rw-r--r--cpukit/libi2c/README_libi2c22
-rw-r--r--cpukit/libi2c/libi2c.c140
-rw-r--r--cpukit/libi2c/libi2c.h70
3 files changed, 177 insertions, 55 deletions
diff --git a/cpukit/libi2c/README_libi2c b/cpukit/libi2c/README_libi2c
index e28fe9c1f1..1dd48faede 100644
--- a/cpukit/libi2c/README_libi2c
+++ b/cpukit/libi2c/README_libi2c
@@ -109,6 +109,28 @@ Any subsequent call to this function will be silently ignored.
Typically the BSP startup code will perform this initialization.
+A proper place for initializing the i2c layer and populating it
+with busses and device drivers (see 'Bus Registration' and
+'Device/Driver Registration' below) is the 'predriver_hook'
+where most facilities (such as malloc, libio) are already
+available. Note, however, that 'stdio' is not yet functional
+at this point and all i2c bus and device drivers should carefully
+avoid using stdio so that other drivers which may build on top
+of i2c devices may be initialized properly (this may happen
+just after 'predriver_hook' when stdio is still not available).
+E.g., drivers listed in the configuration table are initialized
+during this step.
+
+Note that while 'libi2c' could be initialized from the rtems
+configuration table like other drivers there is no easy
+way of populating the i2c framework with bus- and device-
+drivers at this point (unless a special 'i2c' configuration
+table describing the bus layout is implemented in the future).
+
+For the time being, we must rely on the BSP (predriver_hook)
+to initialize the i2c system if it is used by other drivers
+(e.g., the RTC driver may have to use a i2c device).
+
===================
Bus Registration
===================
diff --git a/cpukit/libi2c/libi2c.c b/cpukit/libi2c/libi2c.c
index 7069b35527..7adb793e3a 100644
--- a/cpukit/libi2c/libi2c.c
+++ b/cpukit/libi2c/libi2c.c
@@ -63,6 +63,7 @@
#include <rtems.h>
#include <rtems/error.h>
+#include <rtems/bspIo.h>
#include <rtems/libio.h>
#include <rtems/libi2c.h>
@@ -103,6 +104,8 @@
rtems_device_major_number rtems_libi2c_major;
+static boolean is_initialized = FALSE;
+
static struct i2cbus
{
rtems_libi2c_bus_t *bush;
@@ -132,17 +135,34 @@ static rtems_id libmutex = 0;
|RTEMS_NO_PRIORITY_CEILING \
|RTEMS_LOCAL )
-static rtems_id
-mutexCreate (rtems_name nm)
+/* During early stages of life, stdio is not available */
+
+static void
+safe_printf (const char *fmt, ...)
+{
+va_list ap;
+
+ va_start(ap, fmt);
+ if ( _System_state_Is_up( _System_state_Get() ) )
+ vfprintf( stderr, fmt, ap );
+ else
+ vprintk( fmt, ap );
+ va_end(ap);
+}
+
+static rtems_status_code
+mutexCreate (rtems_name nm, rtems_id *pm)
{
rtems_status_code sc;
- rtems_id rval;
+
if (RTEMS_SUCCESSFUL !=
- (sc = rtems_semaphore_create (nm, 1, MUTEX_ATTS, 0, &rval))) {
- rtems_error (sc, DRVNM " unable to create mutex\n");
- return 0;
+ (sc = rtems_semaphore_create (nm, 1, MUTEX_ATTS, 0, pm))) {
+ if ( _System_state_Is_up( _System_state_Get() ) )
+ rtems_error (sc, DRVNM " unable to create mutex\n");
+ else
+ printk (DRVNM " unable to crate mutex (status code %i)\n", sc);
}
- return rval;
+ return sc;
}
/* Lock a bus avoiding to have a mutex, which is mostly
@@ -155,16 +175,20 @@ mutexCreate (rtems_name nm)
static void
lock_bus (int busno)
{
- struct i2cbus *bus = &busses[busno];
+rtems_status_code sc;
+struct i2cbus *bus = &busses[busno];
+
LIBLOCK ();
if (!bus->waiting) {
+ rtems_id m;
/* nobody is holding the bus mutex - it's not there. Create it on the fly */
- if (!
- (bus->mutex =
- mutexCreate (rtems_build_name ('i', '2', 'c', '0' + busno)))) {
+ sc = mutexCreate (rtems_build_name ('i', '2', 'c', '0' + busno), &m);
+ if ( RTEMS_SUCCESSFUL != sc ) {
LIBUNLOCK ();
rtems_panic (DRVNM " unable to create bus lock");
- }
+ } else {
+ bus->mutex = m;
+ }
}
/* count number of people waiting on this bus; only the last one deletes the mutex */
bus->waiting++;
@@ -186,24 +210,29 @@ unlock_bus (int busno)
}
/* Note that 'arg' is always passed in as NULL */
-static rtems_status_code
-i2c_init (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_init (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
rtems_status_code rval;
+ /* No busses or drivers can be registered at this point;
+ * avoid the macro aborting with an error
DECL_CHECKED_DRV (drv, busno, minor)
+ */
- if (0 == drv) {
- rval = 0;
+ rval = mutexCreate (rtems_build_name ('l', 'I', '2', 'C'), &libmutex);
+
+ if ( RTEMS_SUCCESSFUL == rval ) {
+ is_initialized = TRUE;
+ rtems_libi2c_major = major;
} else {
- /* this is probably never called */
- DISPATCH (rval, initialization_entry, RTEMS_SUCCESSFUL);
+ libmutex = 0;
}
return rval;
}
-static rtems_status_code
-i2c_open (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_open (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
rtems_status_code rval;
@@ -217,8 +246,8 @@ i2c_open (rtems_device_major_number major, rtems_device_minor_number minor,
return rval;
}
-static rtems_status_code
-i2c_close (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_close (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
rtems_status_code rval;
@@ -232,8 +261,8 @@ i2c_close (rtems_device_major_number major, rtems_device_minor_number minor,
return rval;
}
-static rtems_status_code
-i2c_read (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_read (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
int rval; /* int so we can check for negative value */
@@ -262,8 +291,8 @@ i2c_read (rtems_device_major_number major, rtems_device_minor_number minor,
return rval;
}
-static rtems_status_code
-i2c_write (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_write (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
int rval; /* int so we can check for negative value */
@@ -292,8 +321,8 @@ i2c_write (rtems_device_major_number major, rtems_device_minor_number minor,
return rval;
}
-static rtems_status_code
-i2c_ioctl (rtems_device_major_number major, rtems_device_minor_number minor,
+rtems_status_code
+rtems_i2c_ioctl (rtems_device_major_number major, rtems_device_minor_number minor,
void *arg)
{
rtems_status_code rval;
@@ -309,21 +338,19 @@ i2c_ioctl (rtems_device_major_number major, rtems_device_minor_number minor,
/* Our ops just dispatch to the registered drivers */
-static rtems_driver_address_table libi2c_io_ops = {
- initialization_entry: i2c_init,
- open_entry: i2c_open,
- close_entry: i2c_close,
- read_entry: i2c_read,
- write_entry: i2c_write,
- control_entry: i2c_ioctl,
+rtems_driver_address_table rtems_libi2c_io_ops = {
+ initialization_entry: rtems_i2c_init,
+ open_entry: rtems_i2c_open,
+ close_entry: rtems_i2c_close,
+ read_entry: rtems_i2c_read,
+ write_entry: rtems_i2c_write,
+ control_entry: rtems_i2c_ioctl,
};
-
int
rtems_libi2c_initialize ()
{
rtems_status_code sc;
- static boolean is_initialized = FALSE;
if (is_initialized) {
/*
@@ -332,19 +359,23 @@ rtems_libi2c_initialize ()
return 0;
}
- if (!(libmutex = mutexCreate (rtems_build_name ('l', 'I', '2', 'C'))))
- return -1;
-
- sc = rtems_io_register_driver (0, &libi2c_io_ops, &rtems_libi2c_major);
+ /* rtems_io_register_driver does NOT currently check nor report back
+ * the return code of the 'init' operation, so we cannot
+ * rely on return code since it may seem OK even if the driver 'init;
+ * op failed.
+ * Let 'init' handle 'is_initialized'...
+ */
+ sc = rtems_io_register_driver (0, &rtems_libi2c_io_ops, &rtems_libi2c_major);
if (RTEMS_SUCCESSFUL != sc) {
- fprintf (stderr,
+ safe_printf(
DRVNM " Claiming driver slot failed (rtems status code %i)\n",
sc);
- rtems_semaphore_delete (libmutex);
+ if ( libmutex )
+ rtems_semaphore_delete (libmutex);
libmutex = 0;
+ is_initialized = FALSE;
return -1;
}
- is_initialized = TRUE;
return 0;
}
@@ -363,13 +394,12 @@ rtems_libi2c_register_bus (char *name, rtems_libi2c_bus_t * bus)
/* check */
if ('/' != *nmcpy) {
- fprintf (stderr,
- "Bad name; must be an absolute path starting with '/'\n");
+ safe_printf ( DRVNM "Bad name; must be an absolute path starting with '/'\n");
return -RTEMS_INVALID_NAME;
}
/* file must not exist */
if (!stat (nmcpy, &sbuf)) {
- fprintf (stderr, "Bad name; file exists already\n");
+ safe_printf ( DRVNM "Bad name; file exists already\n");
return -RTEMS_INVALID_NAME;
}
@@ -380,20 +410,20 @@ rtems_libi2c_register_bus (char *name, rtems_libi2c_bus_t * bus)
i = stat (nmcpy, &sbuf);
*chpt = tmp;
if (i) {
- fprintf (stderr, "Get %s status failed: %s\n",
- nmcpy,strerror(errno));
+ safe_printf ( DRVNM "Get %s status failed: %s\n",
+ nmcpy, strerror(errno));
return -RTEMS_INVALID_NAME;
}
/* should be a directory since name terminates in '/' */
if (!libmutex) {
- fprintf (stderr, DRVNM " library not initialized\n");
+ safe_printf ( DRVNM " library not initialized\n");
return -RTEMS_NOT_DEFINED;
}
if (bus->size < sizeof (*bus)) {
- fprintf (stderr, DRVNM " bus-ops size too small -- misconfiguration?\n");
+ safe_printf ( DRVNM " bus-ops size too small -- misconfiguration?\n");
return -RTEMS_NOT_CONFIGURED;
}
@@ -653,12 +683,12 @@ rtems_libi2c_register_drv (char *name, rtems_libi2c_drv_t * drvtbl,
rtems_device_minor_number minor;
if (!libmutex) {
- fprintf (stderr, DRVNM " library not initialized\n");
+ safe_printf ( DRVNM " library not initialized\n");
return -RTEMS_NOT_DEFINED;
}
if (name && strchr (name, '/')) {
- fprintf (stderr, "Invalid name: '%s' -- must not contain '/'\n", name);
+ safe_printf ( DRVNM "Invalid name: '%s' -- must not contain '/'\n", name);
return -RTEMS_INVALID_NAME;
}
@@ -668,7 +698,7 @@ rtems_libi2c_register_drv (char *name, rtems_libi2c_drv_t * drvtbl,
}
if (drvtbl->size < sizeof (*drvtbl)) {
- fprintf (stderr, DRVNM " drv-ops size too small -- misconfiguration?\n");
+ safe_printf ( DRVNM " drv-ops size too small -- misconfiguration?\n");
return -RTEMS_NOT_CONFIGURED;
}
@@ -698,7 +728,7 @@ rtems_libi2c_register_drv (char *name, rtems_libi2c_drv_t * drvtbl,
/* note that 'umask' is applied to 'mode' */
if (mknod (str, mode, dev)) {
- fprintf (stderr,
+ safe_printf( DRVNM
"Creating device node failed: %s; you can try to do it manually...\n",
strerror (errno));
}
diff --git a/cpukit/libi2c/libi2c.h b/cpukit/libi2c/libi2c.h
index d243574333..6fa7a53981 100644
--- a/cpukit/libi2c/libi2c.h
+++ b/cpukit/libi2c/libi2c.h
@@ -60,6 +60,76 @@ extern "C" {
/* Initialize the libary - may fail if no semaphore or no driver slot is available */
int rtems_libi2c_initialize ();
+/* Alternatively to rtems_libi2c_initialize() the library can also be
+ * initialized by means of a traditional driver table entry containing
+ * the following entry points:
+ */
+rtems_status_code
+rtems_i2c_init (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+rtems_status_code
+rtems_i2c_open (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+rtems_status_code
+rtems_i2c_close (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+rtems_status_code
+rtems_i2c_read (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+rtems_status_code
+rtems_i2c_write (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+rtems_status_code
+rtems_i2c_ioctl (
+ rtems_device_major_number major,
+ rtems_device_minor_number minor,
+ void *arg);
+
+extern rtems_driver_address_table rtems_libi2c_io_ops;
+
+/* Unfortunately, if you want to add this driver to
+ * a RTEMS configuration table then you need all the
+ * members explicitly :-( (Device_driver_table should
+ * hold pointers to rtems_driver_address_tables rather
+ * than full structs).
+ *
+ * The difficulty is that adding this driver to the
+ * configuration table is not enough; you still need
+ * to populate the framework with low-level bus-driver(s)
+ * and high-level drivers and/or device-files...
+ *
+ * Currently the preferred way is having the BSP
+ * call 'rtems_libi2c_initialize' followed by
+ * 'rtems_libi2c_register_bus' and
+ * 'rtems_libi2c_register_drv' and/or
+ * 'mknod' (for 'raw' device nodes)
+ * from the 'pretasking_hook'.
+ */
+#define RTEMS_LIBI2C_DRIVER_TABLE_ENTRY \
+{ \
+ initialization_entry: rtems_i2c_init, \
+ open_entry: rtems_i2c_open, \
+ close_entry: rtems_i2c_close, \
+ read_entry: rtems_i2c_read, \
+ write_entry: rtems_i2c_write, \
+ control_entry: rtems_i2c_ioctl, \
+}
+
/* Bus Driver API
*
* Bus drivers provide access to low-level i2c functions