[ifxmips]
[openwrt/svn-archive/archive.git] / package / lqtapi / src / tapi / tapi-sysfs-port.c
diff --git a/package/lqtapi/src/tapi/tapi-sysfs-port.c b/package/lqtapi/src/tapi/tapi-sysfs-port.c
new file mode 100644 (file)
index 0000000..f6e5ee0
--- /dev/null
@@ -0,0 +1,107 @@
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/sysfs.h>
+
+#include <linux/err.h>
+#include <linux/tapi/tapi.h>
+
+struct tapi_sysfs_port {
+       struct tapi_device *tdev;
+       unsigned int id;
+       struct kobject kobj;
+};
+
+struct tapi_sysfs_entry {
+       ssize_t (*show)(struct tapi_device *, unsigned int port, char *);
+       ssize_t (*store)(struct tapi_device *, unsigned int port, const char *, size_t);
+       struct attribute attr;
+};
+
+static ssize_t tapi_port_store(struct kobject *kobj, struct attribute *attr,
+       const char *s, size_t len)
+{
+       struct tapi_sysfs_port *port = container_of(kobj, struct tapi_sysfs_port, kobj);
+       struct tapi_sysfs_entry *entry = container_of(attr, struct tapi_sysfs_entry,
+                                                               attr);
+
+       if (!entry->store)
+               return -ENOSYS;
+
+       return entry->store(port->tdev, port->id, s, len);
+}
+
+static ssize_t tapi_port_show(struct kobject *kobj, struct attribute *attr,
+       char *s)
+{
+       return -ENOSYS;
+}
+
+#define TAPI_PORT_ATTR(_name, _mode, _show, _store) \
+       struct tapi_sysfs_entry tapi_port_ ## _name ## _attr = \
+               __ATTR(_name, _mode, _show, _store)
+
+static int tapi_port_store_ring(struct tapi_device *tdev, unsigned int port,
+       const char *s, size_t len)
+{
+       int ret;
+       unsigned long val;
+
+       ret = strict_strtoul(s, 10, &val);
+
+       if (ret)
+               return ret;
+
+       ret = tapi_port_set_ring(tdev, &tdev->ports[port], val);
+       if (ret)
+               return ret;
+       return len;
+}
+
+static TAPI_PORT_ATTR(ring, 0644, NULL, tapi_port_store_ring);
+
+static struct attribute *tapi_port_default_attrs[] = {
+       &tapi_port_ring_attr.attr,
+       NULL,
+};
+
+static void tapi_port_free(struct kobject *kobj)
+{
+       struct tapi_sysfs_port *port = container_of(kobj, struct tapi_sysfs_port, kobj);
+       kfree(port);
+}
+
+static struct sysfs_ops tapi_port_sysfs_ops = {
+       .show           = tapi_port_show,
+       .store          = tapi_port_store,
+};
+
+static struct kobj_type tapi_port_ktype = {
+       .release        = tapi_port_free,
+       .sysfs_ops      = &tapi_port_sysfs_ops,
+       .default_attrs  = tapi_port_default_attrs,
+};
+
+struct tapi_sysfs_port *tapi_port_alloc(struct tapi_device *tdev, unsigned int id)
+{
+       struct tapi_sysfs_port *port;
+       int ret;
+
+       port = kzalloc(sizeof(*port), GFP_KERNEL);
+       port->tdev = tdev;
+       port->id = id;
+
+       ret = kobject_init_and_add(&port->kobj, &tapi_port_ktype, &tdev->dev.kobj,
+               "port%d", id);
+       if (ret) {
+               kfree(port);
+               return ERR_PTR(ret);
+       }
+
+       return port;
+}
+
+void tapi_port_delete(struct tapi_sysfs_port *port)
+{
+       kobject_del(&port->kobj);
+       kobject_put(&port->kobj);
+}