Files
Sebastian Huber 2e50add72a cpukit: Write the driver and PCI Doxygen briefs
The briefs of the block device drivers and the PCI headers named a
topic, not the content of the file.  Five libblock files carried the
same brief "Media implementation.".  Four more carried "RAM disk block
device implementation.".

Write every brief in the style of the tree.  A source brief starts with
"This source file contains" and names the functions the file defines
where there are at most three.  A header brief starts with "This header
file provides".  Put @file, @ingroup and @brief in this order.

The CAN and CAN FD stack keeps its briefs.  Its contributors write them
in a style of their own.

Updates #5717.

Assisted-by: Claude:claude-opus-5 claude-code
Signed-off-by: Sebastian Huber <sebastian.huber@embedded-brains.de>
2026-09-01 20:17:20 +00:00

298 lines
6.4 KiB
C

/**
* @file
*
* @ingroup I2CDevice
*
* @brief This source file contains the implementation of the I2C device
* driver.
*/
/*
* Copyright (C) 2014 embedded brains GmbH & Co. KG
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <dev/i2c/i2c.h>
#include <rtems/imfs.h>
#include <rtems/score/assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
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;
}