summaryrefslogtreecommitdiffstats
path: root/cpukit/libi2c
diff options
context:
space:
mode:
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