mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-16 12:10:38 -04:00
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:
@@ -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)) {
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>] {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user