diff options
Diffstat (limited to 'cpukit/libi2c')
-rw-r--r-- | cpukit/libi2c/README_libi2c | 22 | ||||
-rw-r--r-- | cpukit/libi2c/libi2c.c | 140 | ||||
-rw-r--r-- | cpukit/libi2c/libi2c.h | 70 |
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 |