mirror of
https://github.com/apache/nuttx.git
synced 2026-10-03 12:18:06 +00:00
Permissions (Part 2) Description: In kernel builds, any unprivileged process running on the NuttX device can open /dev/efuse and attempt to read/write fuse content. Reading the fuses may provide valuable information to an attacker controlling the user process. The write operation, in extreme cases where the fuse blocks are not locked, may brick the device. DISCLAIMER: I tried to be strict with the settings, better to relax them later if it's needed. This is part of https://github.com/apache/nuttx/issues/19410 See https://github.com/apache/nuttx/issues/19410 Compiles ok. Signed-off-by: Catalin Visinescu <catalin_visinescu@yahoo.com>
478 lines
14 KiB
C
478 lines
14 KiB
C
/****************************************************************************
|
|
* drivers/sensors/isl29023.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/* WARNING for developers:
|
|
*
|
|
* This driver uses the legacy style of writing sensor drivers for NuttX. The
|
|
* project has since decided to adopt a new sensor framework in order to
|
|
* have a consistent API and feature-set.
|
|
*
|
|
* Sensors which use the uORB framework are typically suffixed "_uorb". You
|
|
* can also visit the documentation about the new sensor framework to learn
|
|
* more.
|
|
*/
|
|
|
|
#warning "This is a deprecated legacy sensor driver."
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <nuttx/debug.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <inttypes.h>
|
|
|
|
#include <nuttx/fs/fs.h>
|
|
#include <nuttx/i2c/i2c_master.h>
|
|
#include <nuttx/kmalloc.h>
|
|
#include <nuttx/random.h>
|
|
|
|
#include <nuttx/sensors/isl29023.h>
|
|
|
|
#if defined(CONFIG_I2C) && defined(CONFIG_SENSORS_ISL29023)
|
|
|
|
/****************************************************************************
|
|
* Pre-Processor Definitions
|
|
****************************************************************************/
|
|
|
|
/* Registers definitions */
|
|
|
|
#define ISL29023_COMMAND_1 0x00
|
|
#define ISL29023_COMMAND_2 0x01
|
|
#define ISL29023_DATA_LSB 0x02
|
|
#define ISL29023_DATA_MSB 0x03
|
|
#define ISL29023_INT_LT_LSB 0x04
|
|
#define ISL29023_INT_LT_MSB 0x05
|
|
#define ISL29023_INT_HT_LSB 0x06
|
|
#define ISL29023_INT_HT_MSB 0x07
|
|
#define ISL29023_TEST 0x08
|
|
|
|
/* Registers definitions */
|
|
|
|
#define ISL29023_RESOLUTION_MASK 0x3
|
|
#define ISL29023_RESOLUTION_SHIFT 0x2
|
|
|
|
#define ISL29023_ALS_RANGE_MASK 0x3
|
|
#define ISL29023_ALS_RANGE_SHIFT 0x0
|
|
|
|
#define ISL29023_OP_MODE_MASK 0x7
|
|
#define ISL29023_OP_MODE_SHIFT 0x5
|
|
|
|
/****************************************************************************
|
|
* Private Types
|
|
****************************************************************************/
|
|
|
|
struct isl29023_dev_s
|
|
{
|
|
FAR struct i2c_master_s *i2c;
|
|
uint8_t addr; /* Address on the I2C bus */
|
|
uint8_t op_mode; /* Defined by isl29023_operational_mode_e */
|
|
uint32_t resolution; /* Sensor ADC res in counts (16..65536) */
|
|
uint32_t range; /* Sensor range (1000..64000) */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Function Prototypes
|
|
****************************************************************************/
|
|
|
|
/* I2C Helpers */
|
|
|
|
static int isl29023_i2c_write(FAR struct isl29023_dev_s *dev,
|
|
FAR const uint8_t *buffer, ssize_t buflen);
|
|
static int isl29023_i2c_read(FAR struct isl29023_dev_s *dev,
|
|
FAR uint8_t *buffer, ssize_t buflen);
|
|
static int isl29023_read_reg(FAR struct isl29023_dev_s *dev,
|
|
const uint8_t regaddr, uint8_t *buffer, size_t buflen);
|
|
static int isl29023_read_lux(FAR struct isl29023_dev_s *dev,
|
|
FAR struct isl29023_data_s *data);
|
|
static int isl29023_set_op_mode(FAR struct isl29023_dev_s *dev,
|
|
uint8_t mode);
|
|
static int isl29023_set_resolution(FAR struct isl29023_dev_s *dev,
|
|
uint8_t res_mode);
|
|
static int isl29023_set_range(FAR struct isl29023_dev_s *dev,
|
|
uint8_t range_mode);
|
|
|
|
/* Driver methods */
|
|
|
|
static ssize_t isl29023_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen);
|
|
static ssize_t isl29023_write(FAR struct file *filep,
|
|
FAR const char *buffer,
|
|
size_t buflen);
|
|
static int isl29023_ioctl(FAR struct file *filep, int cmd,
|
|
unsigned long arg);
|
|
|
|
/****************************************************************************
|
|
* Private Data
|
|
****************************************************************************/
|
|
|
|
static const struct file_operations g_isl29023fops =
|
|
{
|
|
NULL, /* open */
|
|
NULL, /* close */
|
|
isl29023_read, /* read */
|
|
isl29023_write, /* write */
|
|
NULL, /* seek */
|
|
isl29023_ioctl, /* ioctl */
|
|
};
|
|
|
|
/****************************************************************************
|
|
* Private Functions
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_i2c_write
|
|
*
|
|
* Description:
|
|
* Write to the I2C device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int isl29023_i2c_write(FAR struct isl29023_dev_s *dev,
|
|
FAR const uint8_t *buffer, ssize_t buflen)
|
|
{
|
|
struct i2c_msg_s msg;
|
|
int ret;
|
|
|
|
/* Setup for the transfer */
|
|
|
|
msg.frequency = CONFIG_ISL29023_I2C_FREQUENCY,
|
|
msg.addr = dev->addr;
|
|
msg.flags = 0;
|
|
msg.buffer = (FAR uint8_t *)buffer; /* Override const */
|
|
msg.length = buflen;
|
|
|
|
/* Then perform the transfer. */
|
|
|
|
ret = I2C_TRANSFER(dev->i2c, &msg, 1);
|
|
return (ret >= 0) ? OK : ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_i2c_read
|
|
*
|
|
* Description:
|
|
* Read from the I2C device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int isl29023_i2c_read(FAR struct isl29023_dev_s *dev,
|
|
FAR uint8_t *buffer, ssize_t buflen)
|
|
{
|
|
struct i2c_msg_s msg;
|
|
int ret;
|
|
|
|
/* Setup for the transfer */
|
|
|
|
msg.frequency = CONFIG_ISL29023_I2C_FREQUENCY,
|
|
msg.addr = dev->addr,
|
|
msg.flags = I2C_M_READ;
|
|
msg.buffer = buffer;
|
|
msg.length = buflen;
|
|
|
|
/* Then perform the transfer. */
|
|
|
|
ret = I2C_TRANSFER(dev->i2c, &msg, 1);
|
|
return (ret >= 0) ? OK : ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_read_reg
|
|
*
|
|
* Description:
|
|
* Read register from the I2C device.
|
|
*
|
|
****************************************************************************/
|
|
|
|
static int isl29023_read_reg(FAR struct isl29023_dev_s *dev,
|
|
const uint8_t regaddr, uint8_t *buffer,
|
|
size_t buflen)
|
|
{
|
|
int ret;
|
|
|
|
ret = isl29023_i2c_write(dev, ®addr, 1);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: i2c write failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = isl29023_i2c_read(dev, buffer, buflen);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: i2c read failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_read
|
|
****************************************************************************/
|
|
|
|
static ssize_t isl29023_read(FAR struct file *filep, FAR char *buffer,
|
|
size_t buflen)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct isl29023_dev_s *priv = inode->i_private;
|
|
int ret;
|
|
struct isl29023_data_s data;
|
|
|
|
ret = isl29023_read_lux(priv, &data);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: failed to read the sensor: %d\n", ret);
|
|
return (ssize_t)ret;
|
|
}
|
|
else
|
|
{
|
|
if (buflen < sizeof(data))
|
|
{
|
|
return -EIO;
|
|
}
|
|
|
|
memcpy(buffer, &data, sizeof(data));
|
|
}
|
|
|
|
return buflen;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_write
|
|
****************************************************************************/
|
|
|
|
static ssize_t isl29023_write(FAR struct file *filep, FAR const char *buffer,
|
|
size_t buflen)
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_read_lux
|
|
****************************************************************************/
|
|
|
|
static int isl29023_read_lux(FAR struct isl29023_dev_s *dev,
|
|
FAR struct isl29023_data_s *data)
|
|
{
|
|
int ret;
|
|
uint8_t buffer[2];
|
|
|
|
ret = isl29023_read_reg(dev, ISL29023_DATA_LSB, buffer, 2);
|
|
if (ret < 0)
|
|
{
|
|
return ret;
|
|
}
|
|
|
|
data->raw = (buffer[1] << 8) | buffer[0];
|
|
|
|
add_sensor_randomness(data->raw);
|
|
|
|
uint32_t tmp = (data->raw * dev->range) / dev->resolution;
|
|
data->lux = (uint16_t)tmp;
|
|
|
|
sninfo("raw value %8x, lux: %5u\n", data->raw, data->lux);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_set_op_mode
|
|
****************************************************************************/
|
|
|
|
static int isl29023_set_op_mode(FAR struct isl29023_dev_s *dev, uint8_t mode)
|
|
{
|
|
uint8_t buffer[2];
|
|
int ret;
|
|
|
|
ret = isl29023_read_reg(dev, ISL29023_COMMAND_1, &buffer[1], 1);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: i2c read reg failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Clear the mode bits */
|
|
|
|
buffer[1] &= ~(ISL29023_OP_MODE_MASK << ISL29023_OP_MODE_SHIFT);
|
|
mode &= ISL29023_OP_MODE_MASK;
|
|
|
|
/* Modify mode bits */
|
|
|
|
buffer[1] |= mode << ISL29023_OP_MODE_SHIFT;
|
|
buffer[0] = ISL29023_COMMAND_1;
|
|
|
|
dev->op_mode = mode;
|
|
sninfo("mode: %x\n", dev->op_mode);
|
|
|
|
return isl29023_i2c_write(dev, buffer, 2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_set_resolution
|
|
****************************************************************************/
|
|
|
|
static int isl29023_set_resolution(FAR struct isl29023_dev_s *dev,
|
|
uint8_t res_mode)
|
|
{
|
|
uint8_t buffer[2];
|
|
int ret;
|
|
|
|
ret = isl29023_read_reg(dev, ISL29023_COMMAND_2, &buffer[1], 1);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: i2c read reg failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Clear the mode bits */
|
|
|
|
buffer[1] &= ~(ISL29023_RESOLUTION_MASK << ISL29023_RESOLUTION_SHIFT);
|
|
res_mode &= ISL29023_RESOLUTION_MASK;
|
|
|
|
/* Modify mode bits */
|
|
|
|
buffer[1] |= res_mode << ISL29023_RESOLUTION_SHIFT;
|
|
buffer[0] = ISL29023_COMMAND_2;
|
|
|
|
dev->resolution = 1u << (16u - res_mode * 4u);
|
|
sninfo("resolution: %" PRIu32 "\n", dev->resolution);
|
|
|
|
return isl29023_i2c_write(dev, buffer, 2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_set_resolution
|
|
****************************************************************************/
|
|
|
|
static int isl29023_set_range(FAR struct isl29023_dev_s *dev,
|
|
uint8_t range_mode)
|
|
{
|
|
uint8_t buffer[2];
|
|
int ret;
|
|
|
|
ret = isl29023_read_reg(dev, ISL29023_COMMAND_2, &buffer[1], 1);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: i2c read reg failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
/* Clear the mode bits */
|
|
|
|
buffer[1] &= ~(ISL29023_ALS_RANGE_MASK << ISL29023_ALS_RANGE_SHIFT);
|
|
|
|
/* Modify mode bits */
|
|
|
|
range_mode &= ISL29023_ALS_RANGE_MASK;
|
|
buffer[1] |= range_mode << ISL29023_ALS_RANGE_SHIFT;
|
|
buffer[0] = ISL29023_COMMAND_2;
|
|
|
|
dev->range = 1000u * (1u << range_mode) * (1u << range_mode);
|
|
sninfo("range: %" PRIu32 "\n", dev->range);
|
|
|
|
return isl29023_i2c_write(dev, buffer, 2);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Name: isl29023_ioctl
|
|
****************************************************************************/
|
|
|
|
static int isl29023_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|
{
|
|
FAR struct inode *inode = filep->f_inode;
|
|
FAR struct isl29023_dev_s *priv = inode->i_private;
|
|
int ret = OK;
|
|
|
|
switch (cmd)
|
|
{
|
|
/* Write to the COMMAND1 register. Arg: uint8_t value */
|
|
|
|
case SNIOC_SET_OPERATIONAL_MODE:
|
|
ret = isl29023_set_op_mode(priv, (uint8_t)arg);
|
|
sninfo("Set operation mode %d with result %d\n", (uint8_t)arg, ret);
|
|
break;
|
|
|
|
/* Write to the COMMAND2 register. Arg: uint8_t value */
|
|
|
|
case SNIOC_SET_RESOLUTION:
|
|
ret = isl29023_set_resolution(priv, (uint8_t)arg);
|
|
sninfo("Set resolution mode %d with result %d\n", (uint8_t)arg, ret);
|
|
break;
|
|
|
|
/* Write to the COMMAND2 register. Arg: uint8_t value */
|
|
|
|
case SNIOC_SET_RANGE:
|
|
ret = isl29023_set_range(priv, (uint8_t)arg);
|
|
sninfo("Set range mode %d with result %d\n", (uint8_t)arg, ret);
|
|
break;
|
|
|
|
default:
|
|
sninfo("Unrecognized cmd: 0x%04x\n", cmd);
|
|
ret = -ENOTTY;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int isl29023_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
|
|
uint8_t addr)
|
|
{
|
|
FAR struct isl29023_dev_s *priv;
|
|
int ret;
|
|
|
|
priv = (FAR struct isl29023_dev_s *)
|
|
kmm_malloc(sizeof(struct isl29023_dev_s));
|
|
if (priv == NULL)
|
|
{
|
|
snerr("ERROR: Failed to allocate instance\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
priv->i2c = i2c;
|
|
priv->addr = addr;
|
|
priv->resolution = 0x10000;
|
|
priv->range = 64000;
|
|
priv->op_mode = ISL29023_OP_MODE_POWER_DOWN;
|
|
|
|
/* Register the character driver */
|
|
|
|
ret = register_driver(devpath, &g_isl29023fops, 0600, priv);
|
|
if (ret < 0)
|
|
{
|
|
snerr("ERROR: Failed to register driver: %d\n", ret);
|
|
kmm_free(priv);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
#endif /* CONFIG_I2C && CONFIG_SENSORS_ISL29023 */
|