Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:11

0001 /**
0002  * @file
0003  *
0004  * @brief Inter-Integrated Circuit (I2C) Bus Implementation
0005  *
0006  * @ingroup I2CDevice
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 embedded brains GmbH & Co. KG
0011  *
0012  * The license and distribution terms for this file may be
0013  * found in the file LICENSE in this distribution or at
0014  * http://www.rtems.org/license/LICENSE.
0015  */
0016 
0017 #ifdef HAVE_CONFIG_H
0018 #include "config.h"
0019 #endif
0020 
0021 #include <dev/i2c/i2c.h>
0022 
0023 #include <rtems/imfs.h>
0024 #include <rtems/score/assert.h>
0025 
0026 #include <fcntl.h>
0027 #include <stdlib.h>
0028 #include <unistd.h>
0029 
0030 static ssize_t i2c_dev_read(
0031   rtems_libio_t *iop,
0032   void *buffer,
0033   size_t count
0034 )
0035 {
0036   i2c_dev *dev = IMFS_generic_get_context_by_iop(iop);
0037   ssize_t n;
0038 
0039   n = (*dev->read)(dev, buffer, count, iop->offset);
0040   if (n >= 0) {
0041     iop->offset += n;
0042 
0043     return n;
0044   } else {
0045     rtems_set_errno_and_return_minus_one(-n);
0046   }
0047 }
0048 
0049 static ssize_t i2c_dev_write(
0050   rtems_libio_t *iop,
0051   const void *buffer,
0052   size_t count
0053 )
0054 {
0055   i2c_dev *dev = IMFS_generic_get_context_by_iop(iop);
0056   ssize_t n;
0057 
0058   n = (*dev->write)(dev, buffer, count, iop->offset);
0059   if (n >= 0) {
0060     iop->offset += n;
0061 
0062     return n;
0063   } else {
0064     rtems_set_errno_and_return_minus_one(-n);
0065   }
0066 }
0067 
0068 static int i2c_dev_ioctl(
0069   rtems_libio_t *iop,
0070   ioctl_command_t command,
0071   void *arg
0072 )
0073 {
0074   i2c_dev *dev = IMFS_generic_get_context_by_iop(iop);
0075   int err;
0076 
0077   err = (*dev->ioctl)(dev, command, arg);
0078 
0079   if (err == 0) {
0080     return 0;
0081   } else {
0082     rtems_set_errno_and_return_minus_one(-err);
0083   }
0084 }
0085 
0086 static int i2c_dev_fstat(
0087   const rtems_filesystem_location_info_t *loc,
0088   struct stat *buf
0089 )
0090 {
0091   i2c_dev *dev = IMFS_generic_get_context_by_location(loc);
0092 
0093   buf->st_size = (*dev->get_size)(dev);
0094   buf->st_blksize = (*dev->get_block_size)(dev);
0095 
0096   return IMFS_stat(loc, buf);
0097 }
0098 
0099 static const rtems_filesystem_file_handlers_r i2c_dev_handler = {
0100   .open_h = rtems_filesystem_default_open,
0101   .close_h = rtems_filesystem_default_close,
0102   .read_h = i2c_dev_read,
0103   .write_h = i2c_dev_write,
0104   .ioctl_h = i2c_dev_ioctl,
0105   .lseek_h = rtems_filesystem_default_lseek_file,
0106   .fstat_h = i2c_dev_fstat,
0107   .ftruncate_h = rtems_filesystem_default_ftruncate,
0108   .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
0109   .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
0110   .fcntl_h = rtems_filesystem_default_fcntl,
0111   .kqfilter_h = rtems_filesystem_default_kqfilter,
0112   .mmap_h = rtems_filesystem_default_mmap,
0113   .poll_h = rtems_filesystem_default_poll,
0114   .readv_h = rtems_filesystem_default_readv,
0115   .writev_h = rtems_filesystem_default_writev
0116 };
0117 
0118 static void i2c_dev_node_destroy(IMFS_jnode_t *node)
0119 {
0120   i2c_dev *dev;
0121 
0122   dev = IMFS_generic_get_context_by_node(node);
0123   (*dev->destroy)(dev);
0124 
0125   IMFS_node_destroy_default(node);
0126 }
0127 
0128 static const IMFS_node_control i2c_dev_node_control = IMFS_GENERIC_INITIALIZER(
0129   &i2c_dev_handler,
0130   IMFS_node_initialize_generic,
0131   i2c_dev_node_destroy
0132 );
0133 
0134 int i2c_dev_register(
0135   i2c_dev *dev,
0136   const char *dev_path
0137 )
0138 {
0139   int rv;
0140 
0141   rv = IMFS_make_generic_node(
0142     dev_path,
0143     S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
0144     &i2c_dev_node_control,
0145     dev
0146   );
0147   if (rv != 0) {
0148     (*dev->destroy)(dev);
0149   }
0150 
0151   return rv;
0152 }
0153 
0154 static ssize_t i2c_dev_read_default(
0155   i2c_dev *dev,
0156   void *buf,
0157   size_t n,
0158   off_t offset
0159 )
0160 {
0161   (void) dev;
0162   (void) buf;
0163   (void) n;
0164   (void) offset;
0165 
0166   return -EIO;
0167 }
0168 
0169 static ssize_t i2c_dev_write_default(
0170   i2c_dev *dev,
0171   const void *buf,
0172   size_t n,
0173   off_t offset
0174 )
0175 {
0176   (void) dev;
0177   (void) buf;
0178   (void) n;
0179   (void) offset;
0180 
0181   return -EIO;
0182 }
0183 
0184 static int i2c_dev_ioctl_default(
0185   i2c_dev *dev,
0186   ioctl_command_t command,
0187   void *arg
0188 )
0189 {
0190   (void) dev;
0191   (void) command;
0192   (void) arg;
0193 
0194   return -ENOTTY;
0195 }
0196 
0197 static off_t i2c_dev_get_size_default(i2c_dev *dev)
0198 {
0199   (void) dev;
0200 
0201   return 0;
0202 }
0203 
0204 static blksize_t i2c_dev_get_block_size_default(i2c_dev *dev)
0205 {
0206   (void) dev;
0207 
0208   return 1;
0209 }
0210 
0211 static int i2c_dev_do_init(
0212   i2c_dev *dev,
0213   const char *bus_path,
0214   uint16_t address,
0215   void (*destroy)(i2c_dev *dev)
0216 )
0217 {
0218   int rv;
0219 
0220   dev->bus_fd = open(bus_path, O_RDWR);
0221   if (dev->bus_fd < 0) {
0222     (*destroy)(dev);
0223 
0224     return -1;
0225   }
0226 
0227   rv = ioctl(dev->bus_fd, I2C_BUS_GET_CONTROL, &dev->bus);
0228   if (rv != 0) {
0229     (*destroy)(dev);
0230 
0231     return -1;
0232   }
0233 
0234   dev->read = i2c_dev_read_default;
0235   dev->write = i2c_dev_write_default;
0236   dev->ioctl = i2c_dev_ioctl_default;
0237   dev->get_size = i2c_dev_get_size_default;
0238   dev->get_block_size = i2c_dev_get_block_size_default;
0239   dev->destroy = destroy;
0240   dev->address = address;
0241 
0242   return 0;
0243 }
0244 
0245 void i2c_dev_destroy(i2c_dev *dev)
0246 {
0247   int rv;
0248 
0249   rv = close(dev->bus_fd);
0250   _Assert(dev->bus_fd < 0 || rv == 0);
0251   (void) rv;
0252 }
0253 
0254 void i2c_dev_destroy_and_free(i2c_dev *dev)
0255 {
0256   i2c_dev_destroy(dev);
0257   free(dev);
0258 }
0259 
0260 int i2c_dev_init(i2c_dev *dev, const char *bus_path, uint16_t address)
0261 {
0262   return i2c_dev_do_init(dev, bus_path, address, i2c_dev_destroy);
0263 }
0264 
0265 i2c_dev *i2c_dev_alloc_and_init(
0266   size_t size,
0267   const char *bus_path,
0268   uint16_t address
0269 )
0270 {
0271   i2c_dev *dev = NULL;
0272 
0273   if (size >= sizeof(*dev)) {
0274     dev = calloc(1, size);
0275     if (dev != NULL) {
0276       int rv;
0277 
0278       rv = i2c_dev_do_init(dev, bus_path, address, i2c_dev_destroy_and_free);
0279       if (rv != 0) {
0280         return NULL;
0281       }
0282     }
0283   }
0284 
0285   return dev;
0286 }