diff options
-rw-r--r-- | mtac_xdot.c | 168 |
1 files changed, 137 insertions, 31 deletions
diff --git a/mtac_xdot.c b/mtac_xdot.c index 7964f62..eae2f4e 100644 --- a/mtac_xdot.c +++ b/mtac_xdot.c @@ -1,7 +1,8 @@ -#define DRIVER_VERSION "v1.0.0" +#define DRIVER_VERSION "v1.1.0" #define DRIVER_AUTHOR "John Klug <john.klug@multitech.com>" #define DRIVER_DESC "MTS XDOT (LoRa) Accessory Card" #define DRIVER_NAME "mtac-xdot" +#define DEBUG 0 #include <linux/types.h> #include <linux/gpio.h> @@ -19,7 +20,7 @@ static struct gpio_pin gpio_pins_mtcdt_mtac_xdot[] = { .name = "AP1_RESET", .pin = { .gpio = AT91_PIN_PB12, - .flags = GPIOF_OUT_INIT_HIGH, + .flags = GPIOF_OUT_INIT_HIGH, // Only when not flashing .label = "ap1-reset", } }, @@ -30,13 +31,131 @@ static struct gpio_pin gpio_pins_mtcdt_mtac_xdot[] = { .name = "AP2_RESET", .pin = { .gpio = AT91_PIN_PB13, - .flags = GPIOF_OUT_INIT_HIGH, + .flags = GPIOF_OUT_INIT_HIGH, // Only when not flashing .label = "ap2-reset", } }, { }, }; +static int reset_state[NUM_AP]; + +static ssize_t xdot_show_reset(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int value; + int port; + struct gpio_pin *pin; + + log_debug("xdot_show_reset: enter"); + port = mtac_port_from_kobject(kobj); + log_debug("xdot_show_reset: %d",reset_state[port - 1]); + if (port < 1) { + log_error("mtac_port_from_kobject returned %d", port); + return -EINVAL; + } + + pin = mtac_gpio_pin_by_attr_name(attr->attr.name, port); + if (!pin) { + return -ENODEV; + } + + log_debug("mtac_attr_show_ap_gpio_pin: State of mtac mutex is %d",(*(int *)(&mtac_mutex.count))); + mutex_lock(&mtac_mutex); + + value = gpio_get_value(pin->pin.gpio); + if (value < 0) { + mutex_unlock(&mtac_mutex); + return -ENODEV; + } + if(reset_state[port - 1] < 0) { + mutex_unlock(&mtac_mutex); + return sprintf(buf, "Input state: %d\n", value); + } + + mutex_unlock(&mtac_mutex); + return sprintf(buf, "%d\n", value); +} + +static ssize_t xdot_store_reset(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int value, ret; + int port, port_index; + struct gpio_pin *pin; + + log_debug("xdot_store_reset: store %s",buf); + port = mtac_port_from_kobject(kobj); + if (port < 1) { + log_error("mtac_port_from_kobject returned %d", port); + return -EINVAL; + } + port_index = port - 1; + + pin = mtac_gpio_pin_by_attr_name(attr->attr.name, port); + if (!pin) { + return -ENODEV; + } + + if (sscanf(buf, "%i", &value) != 1) { + return -EINVAL; + } + if(value < -1 || value > 1) + return EINVAL; + + log_debug("xdot_store_reset: old %d new %d",reset_state[port_index],value); + + + log_debug("mtac_attr_store_ap_gpio_pin: State of mtac mutex is %d",(*(int *)(&mtac_mutex.count))); + mutex_lock(&mtac_mutex); + + if (value == reset_state[port_index]) { + mutex_unlock(&mtac_mutex); + return count; // No change + } + + // reset_state does not match value + + if (value == -1) { + // Wrong GPIO flags, so change to input + gpio_free(pin->pin.gpio); + ret = gpio_request_one(pin->pin.gpio, GPIOF_IN, pin->pin.label); + if(ret) { + log_error("Could not request pin %s (%d)", pin->name, ret); + reset_state[port_index] = -2; // Invalid state + mutex_unlock(&mtac_mutex); + return EINVAL; + } + reset_state[port_index] = -1; + mutex_unlock(&mtac_mutex); + return count; // Pin is now an input + } + + if (reset_state[port_index] == -1) { + // Wrong GPIO flags, so change to output pin type + gpio_free(pin->pin.gpio); + ret = gpio_request_one(pin->pin.gpio, pin->pin.flags, pin->pin.label); + if(ret) { + log_error("Could not request pin %s (%d)", pin->name, ret); + reset_state[port_index] = -2; // Invalid state + mutex_unlock(&mtac_mutex); + return EINVAL; + } + } + + if (value >= 0) { + // Change the value + gpio_set_value(pin->pin.gpio, value); + reset_state[port_index] = value; + } + + mutex_unlock(&mtac_mutex); + + return count; +} + + ssize_t xdot_show_eui(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { int retval = -1; @@ -119,7 +238,6 @@ static bool xdot_setup(enum ap port) { mtac_set_port_pins(port_index,gpio_pins_mtcdt_mtac_xdot,subdir); - // create the link to the apX directory this card is in // if we're in the first slot, we get plain "XDOT" // if we're in a different slot, we might need to use "XDOT-2" to differentiate @@ -133,25 +251,25 @@ static bool xdot_setup(enum ap port) { } } if (count > 0) { - sprintf(buf, "xdot-%d", count + 1); + sprintf(buf, "xdot-%d", count); } else { sprintf(buf, "xdot"); } ret = sysfs_create_link(mtac_port_info[port_index]->subdirs->parent, mtac_port_info[port_index]->subdirs, buf); if (ret) { - log_error("failed to link [%s] to [%s], %d", buf, mtac_port_info[port_index]->subdirs->name, ret); + log_error("Failed to link [%s] to [%s], %d", buf, mtac_port_info[port_index]->subdirs->name, ret); } attrs = kzalloc(sizeof(struct attribute*) * ap_xdot_attrs_size, GFP_KERNEL); if (! attrs) { - log_error("failed to allocate attribute space for port %d", port); + log_error("Failed to allocate attribute space for port %d", port); return false; } sprintf(buf,"eui"); attr = mtac_create_attribute("eui", MTS_ATTR_MODE_RO); if (! attr) { - log_error("failed to create attribute [%s] for XDOT in port %d", buf, port); + log_error("Failed to create attribute [%s] for XDOT in port %d", buf, port); attrs[index] = NULL; mtac_port_info[port_index]->attr_group.attrs = attrs; return false; @@ -162,18 +280,18 @@ static bool xdot_setup(enum ap port) { sprintf(buf, "reset"); attr = mtac_create_attribute(buf, MTS_ATTR_MODE_RW); if (! attr) { - log_error("failed to create attribute [%s] for ETH in port %d", buf, port); + log_error("Failed to create attribute [%s] for ETH in port %d", buf, port); kfree(attrs); return false; } mtac_port_info[port_index]->attr_group.attrs = attrs; - attr->show = mtac_attr_show_ap_gpio_pin; - attr->store = mtac_attr_store_ap_gpio_pin; + attr->show = xdot_show_reset; + attr->store = xdot_store_reset; attrs[index++] = &attr->attr; - + // add attributes for eeprom contents if (! mtac_add_product_info_attributes(port, attrs, &index)) { - log_error("failed to add product info attributes for XDOT in port %d", port); + log_error("Failed to add product info attributes for XDOT in port %d", port); return false; } @@ -197,12 +315,11 @@ static bool xdot_teardown(enum ap port) { // clean up allocated memory for attributes for (i = 0; i < ap_xdot_attrs_size; i++) { - if (attrs[i]) { - if (attrs[i]->name) - kfree(attrs[i]->name); - - kfree(attrs[i]); - } + if (attrs[i]) { + if (attrs[i]->name) + kfree(attrs[i]->name); + kfree(attrs[i]); + } } kfree(attrs); @@ -248,18 +365,7 @@ static int __init mtac_xdot_init(void) /* We can only tear down our own device */ static void __exit mtac_xdot_exit(void) { - int port_index; - struct mts_ap_eeprom_layout *app; - - for (port_index = 0; port_index < NUM_AP; port_index++) { - app = (struct mts_ap_eeprom_layout *)mts_ap_eeprom[port_index]; - if (app && strstr(app->product_id, PRODUCT_ID_MTAC_XDOT)) { - if (mtac_port_info[port_index]->setup == &xdot_setup) { - mtac_port_info[port_index]->teardown(port_index+1); - kfree(mtac_port_info[port_index]); - } - } - } + mtac_free(PRODUCT_ID_MTAC_XDOT,xdot_setup,"xdot"); log_info("exiting"); } |