blob: 6d3e89214b81ff169d9f37db595270ac6dfbd487 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use bind::compiler::Symbol;
use bind::interpreter::match_bind::{match_bytecode, PropertyKey};
use std::collections::HashMap;
use std::ffi::CStr;
const BIND_PROTOCOL: u64 = 0x0001;
const BIND_AUTOBIND: u64 = 0x0002;
#[repr(u32)]
enum ValueType {
NumberVal = 0,
StringVal = 1,
BoolVal = 2,
}
#[repr(C)]
pub struct device_property_t {
key: u32,
value: u32,
}
#[repr(C)]
pub union value_t {
num_value: u32,
str_value: *const libc::c_char,
bool_value: bool,
}
#[repr(C)]
struct property_value_t {
val_type: ValueType,
value: value_t,
}
#[repr(C)]
pub struct device_str_property_t {
key: *const libc::c_char,
value: property_value_t,
}
fn convert_str(c_str: *const libc::c_char) -> Option<String> {
let str = unsafe { CStr::from_ptr(c_str) };
match str.to_str() {
Ok(value) => Some(value.to_string()),
Err(_) => None,
}
}
fn convert_to_symbol(prop_value: &property_value_t) -> Option<Symbol> {
unsafe {
match prop_value {
property_value_t {
val_type: ValueType::NumberVal,
value: value_t { num_value: val },
} => Some(Symbol::NumberValue(*val as u64)),
property_value_t {
val_type: ValueType::BoolVal,
value: value_t { bool_value: val },
} => Some(Symbol::BoolValue(*val)),
property_value_t {
val_type: ValueType::StringVal,
value: value_t { str_value: val },
} => convert_str(*val).map(|str_val| Symbol::StringValue(str_val)),
}
}
}
#[no_mangle]
pub extern "C" fn str_property_with_string(
key: *const libc::c_char,
value: *const libc::c_char,
) -> device_str_property_t {
device_str_property_t {
key: key,
value: property_value_t {
val_type: ValueType::StringVal,
value: value_t { str_value: value },
},
}
}
#[no_mangle]
pub extern "C" fn str_property_with_int(
key: *const libc::c_char,
value: u32,
) -> device_str_property_t {
device_str_property_t {
key: key,
value: property_value_t {
val_type: ValueType::NumberVal,
value: value_t { num_value: value },
},
}
}
#[no_mangle]
pub extern "C" fn str_property_with_bool(
key: *const libc::c_char,
value: bool,
) -> device_str_property_t {
device_str_property_t {
key: key,
value: property_value_t {
val_type: ValueType::BoolVal,
value: value_t { bool_value: value },
},
}
}
// |bytecode_sz| must match the size of |bytecode_c|. |properties_sz| must
// match the size o |properties_c|.
#[no_mangle]
pub extern "C" fn match_bind_rules(
bytecode_c: *const u8,
bytecode_sz: libc::size_t,
properties_c: *const device_property_t,
properties_sz: libc::size_t,
str_properties_c: *const device_str_property_t,
str_properties_sz: libc::size_t,
protocol_id: u32,
autobind: bool,
) -> bool {
if bytecode_c.is_null() {
return false;
}
let mut device_properties = HashMap::new();
if !properties_c.is_null() {
let properties = unsafe { std::slice::from_raw_parts(properties_c, properties_sz) };
for property in properties.iter() {
device_properties.insert(
PropertyKey::NumberKey(property.key as u64),
Symbol::NumberValue(property.value as u64),
);
}
}
// Insert the protocol ID property if it's missing.
device_properties
.entry(PropertyKey::NumberKey(BIND_PROTOCOL))
.or_insert(Symbol::NumberValue(protocol_id as u64));
device_properties
.entry(PropertyKey::NumberKey(BIND_AUTOBIND))
.or_insert(Symbol::NumberValue(if autobind { 1 } else { 0 }));
if !str_properties_c.is_null() {
let str_properties =
unsafe { std::slice::from_raw_parts(str_properties_c, str_properties_sz) };
for str_property in str_properties.iter() {
let key = convert_str(str_property.key);
let symbol = convert_to_symbol(&str_property.value);
assert!(key.is_some() && symbol.is_some());
device_properties.insert(PropertyKey::StringKey(key.unwrap()), symbol.unwrap());
}
}
let bytecode = unsafe { std::slice::from_raw_parts(bytecode_c, bytecode_sz).to_vec() };
// TODO(fxb/73943): Return the error instead of returning false.
match_bytecode(bytecode, &device_properties).unwrap_or_else(|e| {
println!("Error evaluating the bytecode: {}", e);
false
})
}