static struct kobject *mts_lora_kobject; static void mts_load_lora_port(void) { // create lora/ subdir mts_lora_kobject = kobject_create_and_add("lora", &mts_io_platform_device->dev.kobj); if (sysfs_create_group(mts_lora_kobject, attr_group_lora)) { log_error("failed to create lora attributes"); } } static void mts_teardown_lora_port(void) { // clean up "lora/" kobject if it exists if (mts_lora_kobject) { kobject_put(mts_lora_kobject); } } static ssize_t mts_attr_show_lora_product_info(struct device *dev, struct device_attribute *at, char *buf) { ssize_t value; char label[32]; struct kobject *kobj = (struct kobject *)dev; struct kobj_attribute *attr = (struct kobj_attribute *)at; snprintf(label, sizeof label, "%s/%s", kobj->name, attr->attr.name); if (strcmp(label, "lora/eui") == 0) { value = sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", id_eeprom.lora_eui[0], id_eeprom.lora_eui[1], id_eeprom.lora_eui[2], id_eeprom.lora_eui[3], id_eeprom.lora_eui[4], id_eeprom.lora_eui[5], id_eeprom.lora_eui[6], id_eeprom.lora_eui[7]); } else if (strcmp(label, "lora/product-id") == 0) { value = sprintf(buf, "%.32s\n", id_eeprom.lora_product_id); } else if (strcmp(label, "lora/hw-version") == 0) { value = sprintf(buf, "%.32s\n", id_eeprom.lora_hw_version); } else { log_error("attribute '%s' not found", label); value = -1; } return value; } static ssize_t mts_attr_show_lora_gpio_pin(struct device *dev, struct device_attribute *at, char *buf) { int value; struct gpio_pin *pin; struct kobject *kobj = (struct kobject *)dev; struct kobj_attribute *attr = (struct kobj_attribute *)at; char pin_label[32]; snprintf(pin_label, sizeof pin_label, "%s/%s", kobj->name, attr->attr.name); // ex. lora/reset pin = gpio_pin_by_attr_name(pin_label); if (!pin) { return -ENODEV; } mutex_lock(&mts_io_mutex); if (pin->do_gpio_desc) { value = gpiod_get_value(pin->desc); } else { value = gpio_get_value(pin->pin.gpio); } mutex_unlock(&mts_io_mutex); if (value < 0) { return value; } if (pin->active_low) { value = !value; } return sprintf(buf, "%d\n", value); } static ssize_t mts_attr_store_lora_gpio_pin(struct device *dev, struct device_attribute *at, const char *buf, size_t count) { int value; struct gpio_pin *pin; char pin_label[32]; struct kobject *kobj = (struct kobject *)dev; struct kobj_attribute *attr = (struct kobj_attribute *)at; snprintf(pin_label, sizeof pin_label, "%s/%s", kobj->name, attr->attr.name); // ex. lora/reset pin = gpio_pin_by_attr_name(pin_label); if (!pin) { return -ENODEV; } if (sscanf(buf, "%i", &value) != 1) { return -EINVAL; } if (pin->active_low) { value = !value; } mutex_lock(&mts_io_mutex); if (pin->do_gpio_desc) { gpiod_set_value(pin->desc, value); } else { gpio_set_value(pin->pin.gpio, value); } mutex_unlock(&mts_io_mutex); return count; }