/** * @file * * @brief Inter-Integrated Circuit (I2C) Bus Implementation * * @ingroup I2CDevice */ /* * Copyright (c) 2014 embedded brains GmbH. All rights reserved. * * embedded brains GmbH * Dornierstr. 4 * 82178 Puchheim * Germany * * * The license and distribution terms for this file may be * found in the file LICENSE in this distribution or at * http://www.rtems.org/license/LICENSE. */ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include static ssize_t i2c_dev_read( rtems_libio_t *iop, void *buffer, size_t count ) { i2c_dev *dev = IMFS_generic_get_context_by_iop(iop); ssize_t n; n = (*dev->read)(dev, buffer, count, iop->offset); if (n >= 0) { iop->offset += n; return n; } else { rtems_set_errno_and_return_minus_one(-n); } } static ssize_t i2c_dev_write( rtems_libio_t *iop, const void *buffer, size_t count ) { i2c_dev *dev = IMFS_generic_get_context_by_iop(iop); ssize_t n; n = (*dev->write)(dev, buffer, count, iop->offset); if (n >= 0) { iop->offset += n; return n; } else { rtems_set_errno_and_return_minus_one(-n); } } static int i2c_dev_ioctl( rtems_libio_t *iop, ioctl_command_t command, void *arg ) { i2c_dev *dev = IMFS_generic_get_context_by_iop(iop); int err; err = (*dev->ioctl)(dev, command, arg); if (err == 0) { return 0; } else { rtems_set_errno_and_return_minus_one(-err); } } static int i2c_dev_fstat( const rtems_filesystem_location_info_t *loc, struct stat *buf ) { i2c_dev *dev = IMFS_generic_get_context_by_location(loc); buf->st_size = (*dev->get_size)(dev); buf->st_blksize = (*dev->get_block_size)(dev); return IMFS_stat(loc, buf); } static const rtems_filesystem_file_handlers_r i2c_dev_handler = { .open_h = rtems_filesystem_default_open, .close_h = rtems_filesystem_default_close, .read_h = i2c_dev_read, .write_h = i2c_dev_write, .ioctl_h = i2c_dev_ioctl, .lseek_h = rtems_filesystem_default_lseek_file, .fstat_h = i2c_dev_fstat, .ftruncate_h = rtems_filesystem_default_ftruncate, .fsync_h = rtems_filesystem_default_fsync_or_fdatasync, .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync, .fcntl_h = rtems_filesystem_default_fcntl, .kqfilter_h = rtems_filesystem_default_kqfilter, .mmap_h = rtems_filesystem_default_mmap, .poll_h = rtems_filesystem_default_poll, .readv_h = rtems_filesystem_default_readv, .writev_h = rtems_filesystem_default_writev }; static void i2c_dev_node_destroy(IMFS_jnode_t *node) { i2c_dev *dev; dev = IMFS_generic_get_context_by_node(node); (*dev->destroy)(dev); IMFS_node_destroy_default(node); } static const IMFS_node_control i2c_dev_node_control = IMFS_GENERIC_INITIALIZER( &i2c_dev_handler, IMFS_node_initialize_generic, i2c_dev_node_destroy ); int i2c_dev_register( i2c_dev *dev, const char *dev_path ) { int rv; rv = IMFS_make_generic_node( dev_path, S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, &i2c_dev_node_control, dev ); if (rv != 0) { (*dev->destroy)(dev); } return rv; } static ssize_t i2c_dev_read_default( i2c_dev *dev, void *buf, size_t n, off_t offset ) { (void) dev; (void) buf; (void) n; (void) offset; return -EIO; } static ssize_t i2c_dev_write_default( i2c_dev *dev, const void *buf, size_t n, off_t offset ) { (void) dev; (void) buf; (void) n; (void) offset; return -EIO; } static int i2c_dev_ioctl_default( i2c_dev *dev, ioctl_command_t command, void *arg ) { (void) dev; (void) command; (void) arg; return -ENOTTY; } static off_t i2c_dev_get_size_default(i2c_dev *dev) { (void) dev; return 0; } static blksize_t i2c_dev_get_block_size_default(i2c_dev *dev) { (void) dev; return 1; } static int i2c_dev_do_init( i2c_dev *dev, const char *bus_path, uint16_t address, void (*destroy)(i2c_dev *dev) ) { int rv; dev->bus_fd = open(bus_path, O_RDWR); if (dev->bus_fd < 0) { (*destroy)(dev); return -1; } rv = ioctl(dev->bus_fd, I2C_BUS_GET_CONTROL, &dev->bus); if (rv != 0) { (*destroy)(dev); return -1; } dev->read = i2c_dev_read_default; dev->write = i2c_dev_write_default; dev->ioctl = i2c_dev_ioctl_default; dev->get_size = i2c_dev_get_size_default; dev->get_block_size = i2c_dev_get_block_size_default; dev->destroy = destroy; dev->address = address; return 0; } void i2c_dev_destroy(i2c_dev *dev) { int rv; rv = close(dev->bus_fd); _Assert(dev->bus_fd < 0 || rv == 0); (void) rv; } void i2c_dev_destroy_and_free(i2c_dev *dev) { i2c_dev_destroy(dev); free(dev); } int i2c_dev_init(i2c_dev *dev, const char *bus_path, uint16_t address) { return i2c_dev_do_init(dev, bus_path, address, i2c_dev_destroy); } i2c_dev *i2c_dev_alloc_and_init( size_t size, const char *bus_path, uint16_t address ) { i2c_dev *dev = NULL; if (size >= sizeof(*dev)) { dev = calloc(1, size); if (dev != NULL) { int rv; rv = i2c_dev_do_init(dev, bus_path, address, i2c_dev_destroy_and_free); if (rv != 0) { return NULL; } } } return dev; }