Merge tag 'char-misc-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull Android/IIO fixes from Greg KH:
 "Here is a set of bugfixes for 7.2-rc3 that resolve a bunch of reported
  issues in just the binder and iio codebases. Included in here are:

   - binder driver bugfixes for both the rust and c versions for
     reported problems

   - lots and lots of iio driver bugfixes for lots of reported issues
     (including a hid sensor driver bugfix)

  Full details are in the shortlog, all of these have been in linux-next
  with no reported issues"

* tag 'char-misc-7.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (36 commits)
  iio: event: Fix event FIFO reset race
  iio: imu: inv_icm42600: fix timestamp clock period by using lower value
  iio: light: al3010: fix incorrect scale for the highest gain range
  iio: adc: nxp-sar-adc: Fix the delay calculation in nxp_sar_adc_wait_for()
  iio: light: tsl2591: return actual error from probe IRQ failure
  iio: imu: inv_icm42600: fix timestamping by limiting FIFO reading
  iio: imu: st_lsm6dsx: deselect shub page before reading whoami
  rust_binder: clear freeze listener on node removal
  rust_binder: reject context manager self-transaction
  rust_binder: use a u64 stride when cleaning up the offsets array
  binder: fix UAF in binder_free_transaction()
  binder: fix UAF in binder_thread_release()
  rust_binder: synchronize Rust Binder stats with freeze commands
  binder: cache secctx size before release zeroes it
  rust_binder: fix BINDER_GET_EXTENDED_ERROR
  iio: adc: ad7779: add missing 'select IIO_TRIGGERED_BUFFER' to Kconfig
  iio: adc: ad4130: add missing `select IIO_TRIGGERED_BUFFER` to Kconfig
  iio: adc: ti-ads124s08: Return reset GPIO lookup errors
  iio: temperature: Build mlx90635 with CONFIG_MLX90635
  iio: light: al3320a: add missing REGMAP_I2C to Kconfig
  ...
This commit is contained in:
Linus Torvalds
2026-07-12 12:37:28 -07:00
37 changed files with 362 additions and 117 deletions

View File

@@ -1658,7 +1658,20 @@ static void binder_txn_latency_free(struct binder_transaction *t)
static void binder_free_transaction(struct binder_transaction *t)
{
struct binder_proc *target_proc = t->to_proc;
struct binder_thread *target_thread;
struct binder_proc *target_proc;
spin_lock(&t->lock);
target_proc = t->to_proc;
target_thread = t->to_thread;
/*
* Pin target_thread to keep target_proc alive. Undelivered
* transactions with !target_thread are safe, as target_proc
* can only be the current context there.
*/
if (target_thread)
atomic_inc(&target_thread->tmp_ref);
spin_unlock(&t->lock);
if (target_proc) {
binder_inner_proc_lock(target_proc);
@@ -1672,6 +1685,10 @@ static void binder_free_transaction(struct binder_transaction *t)
t->buffer->transaction = NULL;
binder_inner_proc_unlock(target_proc);
}
if (target_thread)
binder_thread_dec_tmpref(target_thread);
if (trace_binder_txn_latency_free_enabled())
binder_txn_latency_free(t);
/*
@@ -3080,6 +3097,7 @@ static void binder_transaction(struct binder_proc *proc,
int t_debug_id = atomic_inc_return(&binder_last_id);
ktime_t t_start_time = ktime_get();
struct lsm_context lsmctx = { };
size_t lsmctx_aligned_size = 0;
LIST_HEAD(sgc_head);
LIST_HEAD(pf_head);
const void __user *user_buffer = (const void __user *)
@@ -3346,7 +3364,6 @@ static void binder_transaction(struct binder_proc *proc,
if (target_node && target_node->txn_security_ctx) {
u32 secid;
size_t added_size;
security_cred_getsecid(proc->cred, &secid);
ret = security_secid_to_secctx(secid, &lsmctx);
@@ -3358,9 +3375,9 @@ static void binder_transaction(struct binder_proc *proc,
return_error_line = __LINE__;
goto err_get_secctx_failed;
}
added_size = ALIGN(lsmctx.len, sizeof(u64));
extra_buffers_size += added_size;
if (extra_buffers_size < added_size) {
lsmctx_aligned_size = ALIGN(lsmctx.len, sizeof(u64));
extra_buffers_size += lsmctx_aligned_size;
if (extra_buffers_size < lsmctx_aligned_size) {
binder_txn_error("%d:%d integer overflow of extra_buffers_size\n",
thread->pid, proc->pid);
return_error = BR_FAILED_REPLY;
@@ -3397,7 +3414,7 @@ static void binder_transaction(struct binder_proc *proc,
size_t buf_offset = ALIGN(tr->data_size, sizeof(void *)) +
ALIGN(tr->offsets_size, sizeof(void *)) +
ALIGN(extra_buffers_size, sizeof(void *)) -
ALIGN(lsmctx.len, sizeof(u64));
lsmctx_aligned_size;
t->security_ctx = t->buffer->user_data + buf_offset;
err = binder_alloc_copy_to_buffer(&target_proc->alloc,
@@ -3452,7 +3469,7 @@ static void binder_transaction(struct binder_proc *proc,
off_end_offset = off_start_offset + tr->offsets_size;
sg_buf_offset = ALIGN(off_end_offset, sizeof(void *));
sg_buf_end_offset = sg_buf_offset + extra_buffers_size -
ALIGN(lsmctx.len, sizeof(u64));
lsmctx_aligned_size;
off_min = 0;
for (buffer_offset = off_start_offset; buffer_offset < off_end_offset;
buffer_offset += sizeof(binder_size_t)) {

View File

@@ -259,7 +259,7 @@ fn drop(&mut self) {
if let Some(offsets) = info.offsets.clone() {
let view = AllocationView::new(self, offsets.start);
for i in offsets.step_by(size_of::<usize>()) {
for i in offsets.step_by(size_of::<u64>()) {
if view.cleanup_object(i).is_err() {
pr_warn!("Error cleaning up object at offset {}\n", i)
}
@@ -420,7 +420,8 @@ pub(crate) fn transfer_binder_object(
}
fn cleanup_object(&self, index_offset: usize) -> Result {
let offset = self.alloc.read(index_offset)?;
let offset = self.alloc.read::<u64>(index_offset)?;
let offset: usize = offset.try_into().map_err(|_| EINVAL)?;
let header = self.read::<BinderObjectHeader>(offset)?;
match header.type_ {
BINDER_TYPE_WEAK_BINDER | BINDER_TYPE_BINDER => {

View File

@@ -73,20 +73,17 @@ impl fmt::Debug for BinderError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.reply {
BR_FAILED_REPLY => match self.source.as_ref() {
Some(source) => f
.debug_struct("BR_FAILED_REPLY")
.field("source", source)
.finish(),
Some(source) => source.fmt(f),
None => f.pad("BR_FAILED_REPLY"),
},
BR_DEAD_REPLY => f.pad("BR_DEAD_REPLY"),
BR_FROZEN_REPLY => f.pad("BR_FROZEN_REPLY"),
BR_TRANSACTION_PENDING_FROZEN => f.pad("BR_TRANSACTION_PENDING_FROZEN"),
BR_TRANSACTION_COMPLETE => f.pad("BR_TRANSACTION_COMPLETE"),
_ => f
.debug_struct("BinderError")
.field("reply", &self.reply)
.finish(),
_ => match self.source.as_ref() {
Some(source) => source.fmt(f),
None => self.reply.fmt(f),
},
}
}
}

View File

@@ -154,10 +154,17 @@ fn debug_print(&self, m: &SeqFile, prefix: &str, _tprefix: &str) -> Result<()> {
}
impl FreezeListener {
pub(crate) fn on_process_exit(&self, proc: &Arc<Process>) {
/// Called when this freeze listener is cleared abnormally.
///
/// This occurs either because the process exited or because the process dropped its last
/// refcount on the node ref without explicitly removing the freeze listener first.
///
/// The returned `KVVec` is just a value that should be dropped outside of the lock.
pub(crate) fn on_process_cleanup(&self, proc: &Process) -> KVVec<Arc<Process>> {
if !self.is_clearing {
self.node.remove_freeze_listener(proc);
return self.node.remove_freeze_listener(proc);
}
KVVec::new()
}
}

View File

@@ -682,12 +682,13 @@ pub(crate) fn add_freeze_listener(
}
}
pub(crate) fn remove_freeze_listener(&self, p: &Arc<Process>) {
let _unused_capacity;
pub(crate) fn remove_freeze_listener(&self, p: &Process) -> KVVec<Arc<Process>> {
let mut guard = self.owner.inner.lock();
let inner = self.inner.access_mut(&mut guard);
let len = inner.freeze_list.len();
inner.freeze_list.retain(|proc| !Arc::ptr_eq(proc, p));
inner
.freeze_list
.retain(|proc| !core::ptr::eq::<Process>(&**proc, p));
if len == inner.freeze_list.len() {
pr_warn!(
"Could not remove freeze listener for {}\n",
@@ -695,8 +696,9 @@ pub(crate) fn remove_freeze_listener(&self, p: &Arc<Process>) {
);
}
if inner.freeze_list.is_empty() {
_unused_capacity = mem::take(&mut inner.freeze_list);
return mem::take(&mut inner.freeze_list);
}
KVVec::new()
}
pub(crate) fn freeze_list<'a>(&'a self, guard: &'a ProcessInner) -> &'a [Arc<Process>] {

View File

@@ -900,7 +900,11 @@ pub(crate) fn insert_or_update_handle(
pub(crate) fn get_transaction_node(&self, handle: u32) -> BinderResult<NodeRef> {
// When handle is zero, try to get the context manager.
if handle == 0 {
Ok(self.ctx.get_manager_node(true)?)
let node_ref = self.ctx.get_manager_node(true)?;
if core::ptr::eq(self, &*node_ref.node.owner) {
return Err(EINVAL.into());
}
Ok(node_ref)
} else {
Ok(self.get_node_from_handle(handle, true)?)
}
@@ -942,6 +946,8 @@ pub(crate) fn update_ref(
// To preserve original binder behaviour, we only fail requests where the manager tries to
// increment references on itself.
let _to_free_freeze_listener;
let _to_free_freeze_listener_cleanup;
let mut refs = self.node_refs.lock();
if let Some(info) = refs.by_handle.get_mut(&handle) {
if info.node_ref().update(inc, strong) {
@@ -957,6 +963,14 @@ pub(crate) fn update_ref(
unsafe { info.node_ref2().node.remove_node_info(info) };
let id = info.node_ref().node.global_id();
if let Some(freeze) = *info.freeze() {
if let Some(fl) = refs.freeze_listeners.remove(&freeze) {
_to_free_freeze_listener_cleanup = fl.on_process_cleanup(&self);
_to_free_freeze_listener = fl;
}
}
refs.by_handle.remove(&handle);
refs.by_node.remove(&id);
refs.handle_is_present.release_id(handle as usize);
@@ -1380,7 +1394,7 @@ fn deferred_release(self: Arc<Self>) {
// Clean up freeze listeners.
let freeze_listeners = take(&mut self.node_refs.lock().freeze_listeners);
for listener in freeze_listeners.values() {
listener.on_process_exit(&self);
listener.on_process_cleanup(&self);
}
drop(freeze_listeners);

View File

@@ -28,6 +28,9 @@ const char * const binder_command_strings[] = {
"BC_DEAD_BINDER_DONE",
"BC_TRANSACTION_SG",
"BC_REPLY_SG",
"BC_REQUEST_FREEZE_NOTIFICATION",
"BC_CLEAR_FREEZE_NOTIFICATION",
"BC_FREEZE_NOTIFICATION_DONE",
};
const char * const binder_return_strings[] = {
@@ -51,7 +54,9 @@ const char * const binder_return_strings[] = {
"BR_FAILED_REPLY",
"BR_FROZEN_REPLY",
"BR_ONEWAY_SPAM_SUSPECT",
"BR_TRANSACTION_PENDING_FROZEN"
"BR_TRANSACTION_PENDING_FROZEN",
"BR_FROZEN_BINDER",
"BR_CLEAR_FREEZE_NOTIFICATION_DONE",
};
#define CREATE_TRACE_POINTS

View File

@@ -8,8 +8,8 @@
use kernel::sync::atomic::{ordering::Relaxed, Atomic};
use kernel::{ioctl::_IOC_NR, seq_file::SeqFile, seq_print};
const BC_COUNT: usize = _IOC_NR(BC_REPLY_SG) as usize + 1;
const BR_COUNT: usize = _IOC_NR(BR_TRANSACTION_PENDING_FROZEN) as usize + 1;
const BC_COUNT: usize = _IOC_NR(BC_FREEZE_NOTIFICATION_DONE) as usize + 1;
const BR_COUNT: usize = _IOC_NR(BR_CLEAR_FREEZE_NOTIFICATION_DONE) as usize + 1;
pub(crate) static GLOBAL_STATS: BinderStats = BinderStats::new();

View File

@@ -495,9 +495,16 @@ pub(crate) fn debug_print(self: &Arc<Self>, m: &SeqFile, print_all: bool) -> Res
Ok(())
}
pub(crate) fn clear_extended_error(&self, debug_id: usize) {
self.inner.lock().extended_error = ExtendedError::new(debug_id as u32, BR_OK, 0);
}
pub(crate) fn get_extended_error(&self, data: UserSlice) -> Result {
let mut writer = data.writer();
let ee = self.inner.lock().extended_error;
let mut inner = self.inner.lock();
let ee = inner.extended_error;
inner.extended_error = ExtendedError::new(0, BR_OK, 0);
drop(inner);
writer.write(&ee)?;
Ok(())
}
@@ -1109,7 +1116,10 @@ fn unwind_transaction_stack(self: &Arc<Self>) {
inner.pop_transaction_to_reply(thread.as_ref())
} {
let reply = Err(BR_DEAD_REPLY);
if !transaction.from.deliver_single_reply(reply, &transaction) {
if !transaction
.from
.deliver_single_reply(reply, &transaction, None)
{
break;
}
@@ -1121,8 +1131,9 @@ pub(crate) fn deliver_reply(
&self,
reply: Result<DLArc<Transaction>, u32>,
transaction: &DArc<Transaction>,
extended_error: Option<ExtendedError>,
) {
if self.deliver_single_reply(reply, transaction) {
if self.deliver_single_reply(reply, transaction, extended_error) {
transaction.from.unwind_transaction_stack();
}
}
@@ -1136,6 +1147,7 @@ fn deliver_single_reply(
&self,
reply: Result<DLArc<Transaction>, u32>,
transaction: &DArc<Transaction>,
extended_error: Option<ExtendedError>,
) -> bool {
if let Ok(transaction) = &reply {
crate::trace::trace_transaction(true, transaction, Some(&self.task));
@@ -1152,6 +1164,12 @@ fn deliver_single_reply(
return true;
}
if let Some(ee) = extended_error {
if inner.extended_error.command == BR_OK {
inner.extended_error = ee;
}
}
match reply {
Ok(work) => {
inner.push_work(work);
@@ -1222,6 +1240,9 @@ fn read_transaction_info(
info.buffers_size = td.buffers_size as usize;
// SAFETY: Above `read` call initializes all bytes, so this union read is ok.
info.target_handle = unsafe { td.transaction_data.target.handle };
info.debug_id = super::next_debug_id();
Ok(())
}
@@ -1230,6 +1251,8 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
let mut info = TransactionInfo::zeroed();
self.read_transaction_info(cmd, reader, &mut info)?;
self.clear_extended_error(info.debug_id);
let ret = if info.is_reply {
self.reply_inner(&mut info)
} else if info.is_oneway() {
@@ -1239,23 +1262,21 @@ fn transaction(self: &Arc<Self>, cmd: u32, reader: &mut UserSliceReader) -> Resu
};
if let Err(err) = ret {
self.push_return_work(err.reply);
if err.reply != BR_TRANSACTION_COMPLETE {
info.reply = err.reply;
}
if let Some(source) = &err.source {
info.errno = source.to_errno();
self.push_return_work(err.reply);
if let Some(source) = &err.source {
info.errno = source.to_errno();
info.reply = err.reply;
{
let mut ee = self.inner.lock().extended_error;
ee.command = err.reply;
ee.param = source.to_errno();
{
let mut inner = self.inner.lock();
inner.extended_error =
ExtendedError::new(info.debug_id as u32, err.reply, source.to_errno());
}
}
pr_warn!(
"{}:{} transaction to {} failed: {source:?}",
"{}:{} transaction to {} failed: {err:?}",
info.from_pid,
info.from_tid,
info.to_pid
@@ -1320,18 +1341,24 @@ fn reply_inner(self: &Arc<Self>, info: &mut TransactionInfo) -> BinderResult {
let allow_fds = orig.flags & TF_ACCEPT_FDS != 0;
let reply = Transaction::new_reply(self, process, info, allow_fds)?;
self.inner.lock().push_work(completion);
orig.from.deliver_reply(Ok(reply), &orig);
orig.from.deliver_reply(Ok(reply), &orig, None);
Ok(())
})()
.map_err(|mut err| {
// At this point we only return `BR_TRANSACTION_COMPLETE` to the caller, and we must let
// the sender know that the transaction has completed (with an error in this case).
pr_warn!(
"Failure {:?} during reply - delivering BR_FAILED_REPLY to sender.",
err
"{}:{} reply to {} failed: {err:?}",
info.from_pid,
info.from_tid,
info.to_pid
);
let reply = Err(BR_FAILED_REPLY);
orig.from.deliver_reply(reply, &orig);
let param = err.source.as_ref().map_or(0, |e| e.to_errno());
let ee = ExtendedError::new(info.debug_id as u32, err.reply, param);
orig.from
.deliver_reply(Err(BR_FAILED_REPLY), &orig, Some(ee));
err.reply = BR_TRANSACTION_COMPLETE;
err
});

View File

@@ -42,6 +42,7 @@ pub(crate) struct TransactionInfo {
pub(crate) reply: u32,
pub(crate) oneway_spam_suspect: bool,
pub(crate) is_reply: bool,
pub(crate) debug_id: usize,
}
impl TransactionInfo {
@@ -93,7 +94,6 @@ pub(crate) fn new(
from: &Arc<Thread>,
info: &mut TransactionInfo,
) -> BinderResult<DLArc<Self>> {
let debug_id = super::next_debug_id();
let allow_fds = node_ref.node.flags & FLAT_BINDER_FLAG_ACCEPTS_FDS != 0;
let txn_security_ctx = node_ref.node.flags & FLAT_BINDER_FLAG_TXN_SECURITY_CTX != 0;
let mut txn_security_ctx_off = if txn_security_ctx { Some(0) } else { None };
@@ -101,7 +101,7 @@ pub(crate) fn new(
let mut alloc = match from.copy_transaction_data(
to.clone(),
info,
debug_id,
info.debug_id,
allow_fds,
txn_security_ctx_off.as_mut(),
) {
@@ -128,7 +128,7 @@ pub(crate) fn new(
let data_address = alloc.ptr;
Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
debug_id,
debug_id: info.debug_id,
target_node: Some(target_node),
from_parent,
sender_euid: Kuid::current_euid(),
@@ -152,9 +152,8 @@ pub(crate) fn new_reply(
info: &mut TransactionInfo,
allow_fds: bool,
) -> BinderResult<DLArc<Self>> {
let debug_id = super::next_debug_id();
let mut alloc =
match from.copy_transaction_data(to.clone(), info, debug_id, allow_fds, None) {
match from.copy_transaction_data(to.clone(), info, info.debug_id, allow_fds, None) {
Ok(alloc) => alloc,
Err(err) => {
pr_warn!("Failure in copy_transaction_data: {:?}", err);
@@ -165,7 +164,7 @@ pub(crate) fn new_reply(
alloc.set_info_clear_on_drop();
}
Ok(DTRWrap::arc_pin_init(pin_init!(Transaction {
debug_id,
debug_id: info.debug_id,
target_node: None,
from_parent: None,
sender_euid: Kuid::current_euid(),
@@ -394,7 +393,7 @@ fn do_work(
let send_failed_reply = ScopeGuard::new(|| {
if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
let reply = Err(BR_FAILED_REPLY);
self.from.deliver_reply(reply, &self);
self.from.deliver_reply(reply, &self, None);
}
self.drop_outstanding_txn();
});
@@ -478,7 +477,7 @@ fn cancel(self: DArc<Self>) {
// If this is not a reply or oneway transaction, then send a dead reply.
if self.target_node.is_some() && self.flags & TF_ONE_WAY == 0 {
let reply = Err(BR_DEAD_REPLY);
self.from.deliver_reply(reply, &self);
self.from.deliver_reply(reply, &self, None);
}
self.drop_outstanding_txn();

View File

@@ -286,6 +286,54 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
}
EXPORT_SYMBOL_GPL(sensor_hub_get_feature);
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
u32 usage_id, u32 attr_usage_id,
u32 report_id,
enum sensor_hub_read_flags flag,
u32 buffer_size, u8 *buffer)
{
struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev);
struct hid_report *report;
unsigned long flags;
long cycles;
int ret;
report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT);
if (!report)
return -EINVAL;
mutex_lock(hsdev->mutex_ptr);
if (flag == SENSOR_HUB_SYNC) {
memset(&hsdev->pending, 0, sizeof(hsdev->pending));
init_completion(&hsdev->pending.ready);
hsdev->pending.usage_id = usage_id;
hsdev->pending.attr_usage_id = attr_usage_id;
hsdev->pending.max_raw_size = buffer_size;
hsdev->pending.raw_data = buffer;
spin_lock_irqsave(&data->lock, flags);
hsdev->pending.status = true;
spin_unlock_irqrestore(&data->lock, flags);
}
mutex_lock(&data->mutex);
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
mutex_unlock(&data->mutex);
ret = 0;
if (flag == SENSOR_HUB_SYNC) {
cycles = wait_for_completion_interruptible_timeout(&hsdev->pending.ready,
HZ * 5);
if (cycles == 0)
ret = -ETIMEDOUT;
else if (cycles < 0)
ret = cycles;
hsdev->pending.status = false;
}
mutex_unlock(hsdev->mutex_ptr);
return ret;
}
EXPORT_SYMBOL_GPL(sensor_hub_input_attr_read_values);
int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
u32 usage_id,
@@ -478,6 +526,8 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
struct hid_collection *collection = NULL;
void *priv = NULL;
struct hid_sensor_hub_device *hsdev = NULL;
u32 copy_size;
u32 avail;
hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n",
report->id, size, report->type);
@@ -518,12 +568,27 @@ static int sensor_hub_raw_event(struct hid_device *hdev,
hsdev->pending.attr_usage_id ==
report->field[i]->logical)) {
hid_dbg(hdev, "data was pending ...\n");
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
if (hsdev->pending.raw_data)
hsdev->pending.raw_size = sz;
else
hsdev->pending.raw_size = 0;
complete(&hsdev->pending.ready);
if (hsdev->pending.max_raw_size) {
if (hsdev->pending.index < hsdev->pending.max_raw_size) {
avail = hsdev->pending.max_raw_size - hsdev->pending.index;
copy_size = clamp(sz, 0U, avail);
memcpy(hsdev->pending.raw_data + hsdev->pending.index,
ptr, copy_size);
hsdev->pending.index += copy_size;
if (hsdev->pending.index >= hsdev->pending.max_raw_size) {
hsdev->pending.raw_size = hsdev->pending.index;
complete(&hsdev->pending.ready);
}
}
} else {
hsdev->pending.raw_data = kmemdup(ptr, sz, GFP_ATOMIC);
if (hsdev->pending.raw_data)
hsdev->pending.raw_size = sz;
else
hsdev->pending.raw_size = 0;
complete(&hsdev->pending.ready);
}
}
if (callback->capture_sample) {
if (report->field[i]->logical)

View File

@@ -991,6 +991,8 @@ static int __bmc150_accel_fifo_flush(struct iio_dev *indio_dev,
if (samples && count > samples)
count = samples;
count = min_t(u8, count, BMC150_ACCEL_FIFO_LENGTH);
ret = bmc150_accel_fifo_transfer(data, (u8 *)buffer, count);
if (ret)
return ret;

View File

@@ -147,8 +147,9 @@ static int kxsd9_write_raw(struct iio_dev *indio_dev,
if (mask == IIO_CHAN_INFO_SCALE) {
/* Check no integer component */
if (val)
return -EINVAL;
ret = kxsd9_write_scale(indio_dev, val2);
ret = -EINVAL;
else
ret = kxsd9_write_scale(indio_dev, val2);
}
pm_runtime_put_autosuspend(st->dev);

View File

@@ -108,6 +108,7 @@ config AD4130
depends on SPI
depends on GPIOLIB
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IIO_KFIFO_BUF
select REGMAP_SPI
depends on COMMON_CLK
@@ -328,6 +329,7 @@ config AD7298
config AD7380
tristate "Analog Devices AD7380 ADC driver"
depends on SPI_MASTER
select REGMAP
select SPI_OFFLOAD
select IIO_BUFFER
select IIO_BUFFER_DMAENGINE
@@ -452,6 +454,7 @@ config AD7779
depends on SPI
select CRC8
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
select IIO_BACKEND
help
Say yes here to build support for Analog Devices AD777X family

View File

@@ -178,6 +178,8 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
init_completion(&st->completion);
retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
LPC32XXAD_NAME, st);
if (retval < 0) {
@@ -196,8 +198,6 @@ static int lpc32xx_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, iodev);
init_completion(&st->completion);
iodev->name = LPC32XXAD_NAME;
iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE;

View File

@@ -197,13 +197,13 @@ static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
writel(0, NXP_SAR_ADC_IMR(info->regs));
}
static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, unsigned int cycles)
static void nxp_sar_adc_wait_for(struct nxp_sar_adc *info, u64 cycles)
{
u64 rate;
rate = clk_get_rate(info->clk);
if (rate)
ndelay(div64_u64(NSEC_PER_SEC, rate * cycles));
ndelay(div64_u64(NSEC_PER_SEC * cycles, rate));
}
static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)

View File

@@ -282,6 +282,7 @@ static int spear_adc_probe(struct platform_device *pdev)
st = iio_priv(indio_dev);
st->dev = dev;
init_completion(&st->completion);
mutex_init(&st->lock);
/*
@@ -328,8 +329,6 @@ static int spear_adc_probe(struct platform_device *pdev)
spear_adc_configure(st);
init_completion(&st->completion);
indio_dev->name = SPEAR_ADC_MOD_NAME;
indio_dev->info = &spear_adc_info;
indio_dev->modes = INDIO_DIRECT_MODE;

View File

@@ -459,7 +459,11 @@ static int ads1119_triggered_buffer_preenable(struct iio_dev *indio_dev)
if (ret)
return ret;
return i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC);
if (ret)
pm_runtime_put_autosuspend(dev);
return ret;
}
static int ads1119_triggered_buffer_postdisable(struct iio_dev *indio_dev)

View File

@@ -320,7 +320,8 @@ static int ads124s_probe(struct spi_device *spi)
ads124s_priv->reset_gpio = devm_gpiod_get_optional(&spi->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(ads124s_priv->reset_gpio))
dev_info(&spi->dev, "Reset GPIO not defined\n");
return dev_err_probe(&spi->dev, PTR_ERR(ads124s_priv->reset_gpio),
"Failed to get reset GPIO\n");
ads124s_priv->chip_info = &ads124s_chip_info_tbl[spi_id->driver_data];

View File

@@ -498,6 +498,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
u8 *outdata;
struct st_sensor_data *sdata = iio_priv(indio_dev);
unsigned int byte_for_channel;
u32 tmp;
byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits +
ch->scan_type.shift, 8);
@@ -508,12 +509,22 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,
if (err < 0)
return err;
if (byte_for_channel == 1)
*data = (s8)*outdata;
else if (byte_for_channel == 2)
*data = (s16)get_unaligned_le16(outdata);
else if (byte_for_channel == 3)
*data = (s32)sign_extend32(get_unaligned_le24(outdata), 23);
if (byte_for_channel == 1) {
tmp = *outdata;
} else if (byte_for_channel == 2) {
if (ch->scan_type.endianness == IIO_BE)
tmp = get_unaligned_be16(outdata);
else
tmp = get_unaligned_le16(outdata);
} else if (byte_for_channel == 3) {
if (ch->scan_type.endianness == IIO_BE)
tmp = get_unaligned_be24(outdata);
else
tmp = get_unaligned_le24(outdata);
} else {
return -EINVAL;
}
*data = sign_extend32(tmp, BYTES_TO_BITS(byte_for_channel) - 1);
return 0;
}

View File

@@ -1135,26 +1135,33 @@ static int mcp47feb02_probe(struct i2c_client *client)
vdd_uV = ret;
ret = devm_regulator_get_enable_read_voltage(dev, "vref");
if (ret > 0) {
vref_uV = ret;
if (device_property_present(dev, "vref-supply")) {
vref_uV = devm_regulator_get_enable_read_voltage(dev, "vref");
if (vref_uV < 0)
return vref_uV;
if (vref_uV == 0)
return dev_err_probe(dev, -EINVAL, "Vref is 0 uV.\n");
data->use_vref = true;
} else {
vref_uV = 0;
dev_dbg(dev, "using internal band gap as voltage reference.\n");
dev_dbg(dev, "Vref is unavailable.\n");
dev_dbg(dev, "Using internal band gap as voltage reference.\n");
}
if (chip_features->have_ext_vref1) {
ret = devm_regulator_get_enable_read_voltage(dev, "vref1");
if (ret > 0) {
vref1_uV = ret;
data->use_vref1 = true;
} else {
vref1_uV = 0;
dev_dbg(dev, "using internal band gap as voltage reference 1.\n");
dev_dbg(dev, "Vref1 is unavailable.\n");
}
if (chip_features->have_ext_vref1 &&
device_property_present(dev, "vref1-supply")) {
vref1_uV = devm_regulator_get_enable_read_voltage(dev, "vref1");
if (vref1_uV < 0)
return vref1_uV;
if (vref1_uV == 0)
return dev_err_probe(dev, -EINVAL, "Vref1 is 0 uV.\n");
data->use_vref1 = true;
} else {
vref1_uV = 0;
dev_dbg(dev, "Using internal band gap as voltage reference 1.\n");
}
ret = mcp47feb02_init_ctrl_regs(data);

View File

@@ -94,7 +94,7 @@ int devm_adis_probe_trigger(struct adis *adis, struct iio_dev *indio_dev)
else
ret = devm_request_irq(&adis->spi->dev, adis->spi->irq,
&iio_trigger_generic_data_rdy_poll,
adis->irq_flag,
adis->irq_flag | IRQF_NO_THREAD,
indio_dev->name,
adis->trig);
if (ret)

View File

@@ -788,7 +788,8 @@ int bmi160_probe_trigger(struct iio_dev *indio_dev, int irq, u32 irq_type)
ret = devm_request_irq(&indio_dev->dev, irq,
&iio_trigger_generic_data_rdy_poll,
irq_type, "bmi160", data->trig);
irq_type | IRQF_NO_THREAD,
"bmi160", data->trig);
if (ret)
return ret;

View File

@@ -1170,10 +1170,10 @@ struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st)
accel_st->filter = INV_ICM42600_FILTER_AVG_16X;
/*
* clock period is 32kHz (31250ns)
* clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
ts_chip.clock_period = 31250;
ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&accel_st->ts, &ts_chip);

View File

@@ -248,6 +248,7 @@ int inv_icm42600_buffer_update_watermark(struct inv_icm42600_state *st)
/* compute watermark value in bytes */
wm_size = watermark * packet_size;
st->fifo.watermark.value = watermark;
/* changing FIFO watermark requires to turn off watermark interrupt */
ret = regmap_update_bits_check(st->map, INV_ICM42600_REG_INT_SOURCE0,
@@ -454,11 +455,10 @@ int inv_icm42600_buffer_fifo_read(struct inv_icm42600_state *st,
st->fifo.nb.accel = 0;
st->fifo.nb.total = 0;
/* compute maximum FIFO read size */
/* compute maximum FIFO read size (watermark for max = 0 interrupt case) */
if (max == 0)
max_count = sizeof(st->fifo.data);
else
max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
max = st->fifo.watermark.value;
max_count = max * inv_icm42600_get_packet_size(st->fifo.en);
/* read FIFO count value */
raw_fifo_count = (__be16 *)st->buffer;
@@ -574,6 +574,7 @@ int inv_icm42600_buffer_init(struct inv_icm42600_state *st)
st->fifo.watermark.eff_gyro = 1;
st->fifo.watermark.eff_accel = 1;
st->fifo.watermark.value = 1;
/*
* Default FIFO configuration (bits 7 to 5)

View File

@@ -34,6 +34,7 @@ struct inv_icm42600_fifo {
unsigned int accel;
unsigned int eff_gyro;
unsigned int eff_accel;
unsigned int value;
} watermark;
size_t count;
struct {

View File

@@ -755,10 +755,10 @@ struct iio_dev *inv_icm42600_gyro_init(struct inv_icm42600_state *st)
}
/*
* clock period is 32kHz (31250ns)
* clock period is 8kHz (125000ns)
* jitter is +/- 2% (20 per mille)
*/
ts_chip.clock_period = 31250;
ts_chip.clock_period = 125000;
ts_chip.jitter = 20;
ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr);
inv_sensors_timestamp_init(&gyro_st->ts, &ts_chip);

View File

@@ -1712,6 +1712,26 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
return -ENODEV;
}
hw->settings = &st_lsm6dsx_sensor_settings[i];
if (hw->settings->shub_settings.page_mux.addr) {
/*
* If the IMU has the shub page selected on init, for example
* after a CPU watchdog reset while the page is selected, the
* regular register space is shadowed. While the regular
* register space is shadowed, the registers needed for
* initializing the IMU are not available.
*
* Unconditionally clear the shub page selection to ensure
* normal register access.
*/
err = st_lsm6dsx_set_page(hw, false);
if (err < 0) {
dev_err(hw->dev, "failed to clear shub page\n");
return err;
}
}
err = regmap_read(hw->regmap, ST_LSM6DSX_REG_WHOAMI_ADDR, &data);
if (err < 0) {
dev_err(hw->dev, "failed to read whoami register\n");
@@ -1724,7 +1744,6 @@ static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw, int id,
}
*name = st_lsm6dsx_sensor_settings[i].id[j].name;
hw->settings = &st_lsm6dsx_sensor_settings[i];
return 0;
}

View File

@@ -207,6 +207,8 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
goto unlock;
}
kfifo_reset_out(&ev_int->det_events);
iio_device_get(indio_dev);
fd = anon_inode_getfd("iio:event", &iio_event_chrdev_fileops,
@@ -214,10 +216,7 @@ static int iio_event_getfd(struct iio_dev *indio_dev)
if (fd < 0) {
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
iio_device_put(indio_dev);
} else {
kfifo_reset_out(&ev_int->det_events);
}
unlock:
mutex_unlock(&iio_dev_opaque->mlock);
return fd;

View File

@@ -45,6 +45,7 @@ config ADUX1020
config AL3000A
tristate "AL3000a ambient light sensor"
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3000a
@@ -55,6 +56,7 @@ config AL3000A
config AL3010
tristate "AL3010 ambient light sensor"
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3010
@@ -65,6 +67,7 @@ config AL3010
config AL3320A
tristate "AL3320A ambient light sensor"
select REGMAP_I2C
depends on I2C
help
Say Y here if you want to build a driver for the Dyna Image AL3320A

View File

@@ -41,7 +41,7 @@ enum al3xxxx_range {
};
static const int al3010_scales[][2] = {
{0, 1187200}, {0, 296800}, {0, 74200}, {0, 18600}
{ 1, 187200 }, { 0, 296800 }, { 0, 74200 }, { 0, 18600 },
};
static const struct regmap_config al3010_regmap_config = {

View File

@@ -258,7 +258,7 @@ static int gp2ap002_read_raw(struct iio_dev *indio_dev,
case IIO_LIGHT:
ret = gp2ap002_get_lux(gp2ap002);
if (ret < 0)
return ret;
goto out;
*val = ret;
ret = IIO_VAL_INT;
goto out;

View File

@@ -1070,10 +1070,8 @@ static int tsl2591_probe(struct i2c_client *client)
NULL, tsl2591_event_handler,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tsl2591_irq", indio_dev);
if (ret) {
dev_err_probe(&client->dev, ret, "IRQ request error\n");
return -EINVAL;
}
if (ret)
return ret;
indio_dev->info = &tsl2591_info;
} else {
indio_dev->info = &tsl2591_info_no_irq;

View File

@@ -85,6 +85,13 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
long mask)
{
struct dev_rot_state *rot_state = iio_priv(indio_dev);
struct hid_sensor_hub_device *hsdev = rot_state->common_attributes.hsdev;
struct hid_sensor_hub_attribute_info *info = &rot_state->quaternion;
u32 usage_id = HID_USAGE_SENSOR_ORIENT_QUATERNION;
union {
s16 val16[4];
s32 val32[4];
} raw_buf;
int ret_type;
int i;
@@ -94,8 +101,37 @@ static int dev_rot_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
if (size >= 4) {
for (i = 0; i < 4; ++i)
vals[i] = rot_state->scan.sampled_vals[i];
if (info->size <= 0 || info->size > sizeof(raw_buf))
return -EINVAL;
hid_sensor_power_state(&rot_state->common_attributes, true);
ret_type = sensor_hub_input_attr_read_values(hsdev,
hsdev->usage,
usage_id,
info->report_id,
SENSOR_HUB_SYNC,
info->size,
(u8 *)&raw_buf);
hid_sensor_power_state(&rot_state->common_attributes, false);
if (ret_type < 0)
return ret_type;
switch (info->size) {
case sizeof(raw_buf.val16):
for (i = 0; i < ARRAY_SIZE(raw_buf.val16); i++)
vals[i] = raw_buf.val16[i];
break;
case sizeof(raw_buf.val32):
for (i = 0; i < ARRAY_SIZE(raw_buf.val32); i++)
vals[i] = raw_buf.val32[i];
break;
default:
return -EINVAL;
}
ret_type = IIO_VAL_INT_MULTIPLE;
*val_len = 4;
} else

View File

@@ -106,18 +106,18 @@ static int mpl115_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_PROCESSED:
pm_runtime_get_sync(data->dev);
ret = mpl115_comp_pressure(data, val, val2);
pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
pm_runtime_put_autosuspend(data->dev);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_RAW:
pm_runtime_get_sync(data->dev);
/* temperature -5.35 C / LSB, 472 LSB is 25 C */
ret = mpl115_read_temp(data);
pm_runtime_put_autosuspend(data->dev);
if (ret < 0)
return ret;
pm_runtime_put_autosuspend(data->dev);
*val = ret >> 6;
return IIO_VAL_INT;

View File

@@ -13,7 +13,7 @@ obj-$(CONFIG_MAX31865) += max31865.o
obj-$(CONFIG_MCP9600) += mcp9600.o
obj-$(CONFIG_MLX90614) += mlx90614.o
obj-$(CONFIG_MLX90632) += mlx90632.o
obj-$(CONFIG_MLX90632) += mlx90635.o
obj-$(CONFIG_MLX90635) += mlx90635.o
obj-$(CONFIG_TMP006) += tmp006.o
obj-$(CONFIG_TMP007) += tmp007.o
obj-$(CONFIG_TMP117) += tmp117.o

View File

@@ -43,6 +43,8 @@ struct hid_sensor_hub_attribute_info {
* @attr_usage_id: Usage Id of a field, e.g. X-axis for a gyro.
* @raw_size: Response size for a read request.
* @raw_data: Place holder for received response.
* @index: Current write index into raw_data for multi-byte reads.
* @max_raw_size: Total buffer size for multi-byte reads; 0 for single-value reads.
*/
struct sensor_hub_pending {
bool status;
@@ -51,6 +53,8 @@ struct sensor_hub_pending {
u32 attr_usage_id;
int raw_size;
u8 *raw_data;
u32 index;
u32 max_raw_size;
};
/**
@@ -183,6 +187,27 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
bool is_signed
);
/**
* sensor_hub_input_attr_read_values() - Synchronous multi-byte read request
* @hsdev: Hub device instance.
* @usage_id: Attribute usage id of parent physical device as per spec
* @attr_usage_id: Attribute usage id as per spec
* @report_id: Report id to look for
* @flag: Synchronous or asynchronous read
* @buffer_size: Size of the buffer in bytes
* @buffer: Buffer to store the read data
*
* Issues a synchronous or asynchronous read request for an input attribute,
* accumulating data into the provided buffer until it is full.
* Return: 0 on success, -ETIMEDOUT if the device did not respond, or a
* negative error code.
*/
int sensor_hub_input_attr_read_values(struct hid_sensor_hub_device *hsdev,
u32 usage_id, u32 attr_usage_id,
u32 report_id,
enum sensor_hub_read_flags flag,
u32 buffer_size, u8 *buffer);
/**
* sensor_hub_set_feature() - Feature set request
* @hsdev: Hub device instance.