summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mtac_xdot.c168
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");
}