summaryrefslogtreecommitdiff
path: root/xpp/xbus-sysfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'xpp/xbus-sysfs.c')
-rw-r--r--xpp/xbus-sysfs.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/xpp/xbus-sysfs.c b/xpp/xbus-sysfs.c
new file mode 100644
index 0000000..f444b50
--- /dev/null
+++ b/xpp/xbus-sysfs.c
@@ -0,0 +1,256 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, Xorcom
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+# warning "This module is tested only with 2.6 kernels"
+#endif
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#ifdef PROTOCOL_DEBUG
+#include <linux/ctype.h>
+#endif
+#include <linux/workqueue.h>
+#include <linux/device.h>
+#include <linux/delay.h> /* for msleep() to debug */
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xbus-core.h"
+#ifdef XPP_DEBUGFS
+#include "xpp_log.h"
+#endif
+#include "zap_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+/* Command line parameters */
+extern int print_dbg;
+
+
+/* Kernel versions... */
+/*
+ * Hotplug replaced with uevent in 2.6.16
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
+#define OLD_HOPLUG_SUPPORT // for older kernels
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+#define DEVICE_ATTR_FUNC(name,dev,buf) \
+ ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
+#else
+#define DEVICE_ATTR_FUNC(name,dev,buf) \
+ ssize_t name(struct device *dev, char *buf)
+#endif
+
+/*--------- Sysfs Bus handling ----*/
+static int xpp_bus_match(struct device *dev, struct device_driver *driver)
+{
+ DBG("dev->bus_id = %s, driver->name = %s\n", dev->bus_id, driver->name);
+ return 1;
+}
+
+#ifdef OLD_HOPLUG_SUPPORT
+static int xpp_bus_hotplug(struct device *dev, char **envp, int envnum, char *buff, int bufsize)
+{
+ xbus_t *xbus;
+
+ if(!dev)
+ return -ENODEV;
+ xbus = dev_to_xbus(dev);
+ envp[0] = buff;
+ if(snprintf(buff, bufsize, "XBUS_NAME=%s", xbus->busname) >= bufsize)
+ return -ENOMEM;
+ envp[1] = NULL;
+ return 0;
+}
+#else
+
+#define XBUS_ADD_UEVENT_VAR(fmt, val...) \
+ do { \
+ int err = add_uevent_var(envp, num_envp, &i, \
+ buffer, buffer_size, &len, \
+ fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
+static int xpp_bus_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+{
+ xbus_t *xbus;
+ int i = 0;
+ int len = 0;
+
+ if(!dev)
+ return -ENODEV;
+ xbus = dev_to_xbus(dev);
+ DBG("bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
+ XBUS_ADD_UEVENT_VAR("XBUS_NUM=%02d", xbus->num);
+ XBUS_ADD_UEVENT_VAR("XBUS_NAME=%s", xbus->busname);
+ envp[i] = NULL;
+ return 0;
+}
+#endif
+
+static void xpp_bus_release(struct device *dev)
+{
+ DBG("\n");
+}
+
+static void xpp_dev_release(struct device *dev)
+{
+ xbus_t *xbus;
+
+ BUG_ON(!dev);
+ xbus = dev_to_xbus(dev);
+ XBUS_DBG(xbus, "\n");
+}
+
+static struct bus_type xpp_bus_type = {
+ .name = "astribanks",
+ .match = xpp_bus_match,
+#ifdef OLD_HOPLUG_SUPPORT
+ .hotplug = xpp_bus_hotplug,
+#else
+ .uevent = xpp_bus_uevent,
+#endif
+};
+
+static struct device xpp_bus = {
+ .bus_id = "xppbus",
+ .release = xpp_bus_release
+};
+
+static struct device_driver xpp_driver = {
+ .name = "xppdrv",
+ .bus = &xpp_bus_type,
+#ifndef OLD_HOPLUG_SUPPORT
+ .owner = THIS_MODULE
+#endif
+};
+
+int register_xpp_bus(void)
+{
+ int ret;
+
+ if((ret = bus_register(&xpp_bus_type)) < 0) {
+ ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
+ goto failed_bus;
+ }
+ if((ret = device_register(&xpp_bus)) < 0) {
+ ERR("%s: registration of xpp_bus failed. Error number %d",
+ __FUNCTION__, ret);
+ goto failed_busdevice;
+ }
+ if((ret = driver_register(&xpp_driver)) < 0) {
+ ERR("%s: driver_register failed. Error number %d", __FUNCTION__, ret);
+ goto failed_driver;
+ }
+ return 0;
+failed_driver:
+ device_unregister(&xpp_bus);
+failed_busdevice:
+ bus_unregister(&xpp_bus_type);
+failed_bus:
+ return ret;
+}
+
+void unregister_xpp_bus(void)
+{
+ driver_unregister(&xpp_driver);
+ device_unregister(&xpp_bus);
+ bus_unregister(&xpp_bus_type);
+}
+
+/*--------- Sysfs Device handling ----*/
+static DEVICE_ATTR_FUNC(connector_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->busdesc);
+ return ret;
+}
+
+static DEVICE_ATTR_FUNC(status_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", (xbus->hardware_exists)?"connected":"missing");
+ return ret;
+}
+
+static DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL);
+static DEVICE_ATTR(status, S_IRUGO, status_show, NULL);
+
+void xbus_sysfs_remove(xbus_t *xbus)
+{
+ struct device *astribank;
+
+ BUG_ON(!xbus);
+ XBUS_DBG(xbus, "\n");
+ astribank = &xbus->astribank;
+ BUG_ON(!astribank);
+ device_remove_file(&xbus->astribank, &dev_attr_status);
+ device_remove_file(&xbus->astribank, &dev_attr_connector);
+ device_unregister(&xbus->astribank);
+}
+
+int xbus_sysfs_create(xbus_t *xbus)
+{
+ struct device *astribank;
+ int ret = 0;
+
+ BUG_ON(!xbus);
+ astribank = &xbus->astribank;
+ BUG_ON(!astribank);
+ XBUS_DBG(xbus, "\n");
+ device_initialize(astribank);
+ astribank->bus = &xpp_bus_type;
+ astribank->parent = &xpp_bus;
+ snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num);
+ astribank->driver_data = NULL; /* FIXME: add some usefull data */
+ astribank->release = xpp_dev_release;
+ ret = device_register(astribank);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_add failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_connector);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+ ret = device_create_file(astribank, &dev_attr_status);
+ if(ret) {
+ XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
+ goto out;
+ }
+out:
+ return ret;
+}