@@ -107,6 +107,12 @@ static int cdx_unregister_device(struct device *dev,
return 0;
}
+static void cdx_unregister_devices(struct bus_type *bus)
+{
+ /* Reset all the devices attached to cdx bus */
+ bus_for_each_dev(bus, NULL, NULL, cdx_unregister_device);
+}
+
/**
* cdx_match_one_device - Tell if a CDX device structure has a matching
* CDX device id structure
@@ -196,11 +202,163 @@ static int cdx_dma_configure(struct device *dev)
return 0;
}
+static ssize_t vendor_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return sprintf(buf, "0x%x\n", cdx_dev->vendor);
+}
+static DEVICE_ATTR_RO(vendor);
+
+static ssize_t device_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return sprintf(buf, "0x%x\n", cdx_dev->device);
+}
+static DEVICE_ATTR_RO(device);
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret = 0;
+ bool reset = count > 0 && *buf != '0';
+
+ if (!reset)
+ return count;
+
+ ret = reset_cdx_device(dev, NULL);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_WO(reset);
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return sprintf(buf, "cdx:v%08Xd%d\n", cdx_dev->vendor,
+ cdx_dev->device);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static ssize_t driver_override_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+ const char *old = cdx_dev->driver_override;
+ char *driver_override;
+ char *cp;
+
+ if (WARN_ON(dev->bus != &cdx_bus_type))
+ return -EINVAL;
+
+ if (count >= (PAGE_SIZE - 1))
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, count, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ cp = strchr(driver_override, '\n');
+ if (cp)
+ *cp = '\0';
+
+ if (strlen(driver_override)) {
+ cdx_dev->driver_override = driver_override;
+ } else {
+ kfree(driver_override);
+ cdx_dev->driver_override = NULL;
+ }
+
+ kfree(old);
+
+ return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(dev);
+
+ return snprintf(buf, PAGE_SIZE, "%s\n", cdx_dev->driver_override);
+}
+static DEVICE_ATTR_RW(driver_override);
+
+static struct attribute *cdx_dev_attrs[] = {
+ &dev_attr_reset.attr,
+ &dev_attr_vendor.attr,
+ &dev_attr_device.attr,
+ &dev_attr_modalias.attr,
+ &dev_attr_driver_override.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(cdx_dev);
+
+static ssize_t rescan_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ bool rescan = count > 0 && *buf != '0';
+ int ret = 0;
+
+ if (!rescan)
+ return count;
+
+ if (!cdx_controller)
+ return -EINVAL;
+
+ /* Unregister all the devices on the bus */
+ cdx_unregister_devices(&cdx_bus_type);
+
+ /* Rescan all the devices */
+ ret = cdx_controller->ops.scan(cdx_controller);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static BUS_ATTR_WO(rescan);
+
+static ssize_t reset_all_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ bool reset = count > 0 && *buf != '0';
+ int ret = 0;
+
+ if (!reset)
+ return count;
+
+ /* Reset all the devices attached to cdx bus */
+ ret = bus_for_each_dev(bus, NULL, NULL, reset_cdx_device);
+ if (ret) {
+ pr_err("error in CDX bus reset\n");
+ return 0;
+ }
+
+ return count;
+}
+static BUS_ATTR_WO(reset_all);
+
+static struct attribute *cdx_bus_attrs[] = {
+ &bus_attr_rescan.attr,
+ &bus_attr_reset_all.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(cdx_bus);
+
struct bus_type cdx_bus_type = {
.name = "cdx",
.match = cdx_bus_match,
.remove = cdx_remove,
.dma_configure = cdx_dma_configure,
+ .dev_groups = cdx_dev_groups,
+ .bus_groups = cdx_bus_groups,
};
EXPORT_SYMBOL_GPL(cdx_bus_type);