summaryrefslogtreecommitdiffstats
path: root/sys/compat/linuxkpi/common/src/linux_compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linuxkpi/common/src/linux_compat.c')
-rw-r--r--sys/compat/linuxkpi/common/src/linux_compat.c193
1 files changed, 164 insertions, 29 deletions
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index 91ec693..4d48519 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -77,9 +77,9 @@ MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat");
#undef cdev
#define RB_ROOT(head) (head)->rbh_root
-struct kobject class_root;
-struct device linux_rootdev;
-struct class miscclass;
+struct kobject linux_class_root;
+struct device linux_root_device;
+struct class linux_class_misc;
struct list_head pci_drivers;
struct list_head pci_devices;
struct net init_net;
@@ -151,13 +151,13 @@ kobject_set_name(struct kobject *kobj, const char *fmt, ...)
return (error);
}
-static inline int
+static int
kobject_add_complete(struct kobject *kobj, struct kobject *parent)
{
- struct kobj_type *t;
+ const struct kobj_type *t;
int error;
- kobj->parent = kobject_get(parent);
+ kobj->parent = parent;
error = sysfs_create_dir(kobj);
if (error == 0 && kobj->ktype && kobj->ktype->default_attrs) {
struct attribute **attr;
@@ -191,16 +191,13 @@ kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...)
}
void
-kobject_release(struct kref *kref)
+linux_kobject_release(struct kref *kref)
{
struct kobject *kobj;
char *name;
kobj = container_of(kref, struct kobject, kref);
sysfs_remove_dir(kobj);
- if (kobj->parent)
- kobject_put(kobj->parent);
- kobj->parent = NULL;
name = kobj->name;
if (kobj->ktype && kobj->ktype->release)
kobj->ktype->release(kobj);
@@ -208,28 +205,131 @@ kobject_release(struct kref *kref)
}
static void
-kobject_kfree(struct kobject *kobj)
+linux_kobject_kfree(struct kobject *kobj)
{
kfree(kobj);
}
static void
-kobject_kfree_name(struct kobject *kobj)
+linux_kobject_kfree_name(struct kobject *kobj)
{
if (kobj) {
kfree(kobj->name);
}
}
-struct kobj_type kfree_type = { .release = kobject_kfree };
+const struct kobj_type linux_kfree_type = {
+ .release = linux_kobject_kfree
+};
static void
-dev_release(struct device *dev)
+linux_device_release(struct device *dev)
{
- pr_debug("dev_release: %s\n", dev_name(dev));
+ pr_debug("linux_device_release: %s\n", dev_name(dev));
kfree(dev);
}
+static ssize_t
+linux_class_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct class, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_class_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct class_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct class_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct class, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static void
+linux_class_release(struct kobject *kobj)
+{
+ struct class *class;
+
+ class = container_of(kobj, struct class, kobj);
+ if (class->class_release)
+ class->class_release(class);
+}
+
+static const struct sysfs_ops linux_class_sysfs = {
+ .show = linux_class_show,
+ .store = linux_class_store,
+};
+
+const struct kobj_type linux_class_ktype = {
+ .release = linux_class_release,
+ .sysfs_ops = &linux_class_sysfs
+};
+
+static void
+linux_dev_release(struct kobject *kobj)
+{
+ struct device *dev;
+
+ dev = container_of(kobj, struct device, kobj);
+ /* This is the precedence defined by linux. */
+ if (dev->release)
+ dev->release(dev);
+ else if (dev->class && dev->class->dev_release)
+ dev->class->dev_release(dev);
+}
+
+static ssize_t
+linux_dev_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->show)
+ error = dattr->show(container_of(kobj, struct device, kobj),
+ dattr, buf);
+ return (error);
+}
+
+static ssize_t
+linux_dev_store(struct kobject *kobj, struct attribute *attr, const char *buf,
+ size_t count)
+{
+ struct device_attribute *dattr;
+ ssize_t error;
+
+ dattr = container_of(attr, struct device_attribute, attr);
+ error = -EIO;
+ if (dattr->store)
+ error = dattr->store(container_of(kobj, struct device, kobj),
+ dattr, buf, count);
+ return (error);
+}
+
+static const struct sysfs_ops linux_dev_sysfs = {
+ .show = linux_dev_show,
+ .store = linux_dev_store,
+};
+
+const struct kobj_type linux_dev_ktype = {
+ .release = linux_dev_release,
+ .sysfs_ops = &linux_dev_sysfs
+};
+
struct device *
device_create(struct class *class, struct device *parent, dev_t devt,
void *drvdata, const char *fmt, ...)
@@ -242,7 +342,7 @@ device_create(struct class *class, struct device *parent, dev_t devt,
dev->class = class;
dev->devt = devt;
dev->driver_data = drvdata;
- dev->release = dev_release;
+ dev->release = linux_device_release;
va_start(args, fmt);
kobject_set_name_vargs(&dev->kobj, fmt, args);
va_end(args);
@@ -252,7 +352,7 @@ device_create(struct class *class, struct device *parent, dev_t devt,
}
int
-kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
+kobject_init_and_add(struct kobject *kobj, const struct kobj_type *ktype,
struct kobject *parent, const char *fmt, ...)
{
va_list args;
@@ -1002,6 +1102,41 @@ destroy_workqueue(struct workqueue_struct *wq)
}
static void
+linux_cdev_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ if (cdev->cdev)
+ destroy_dev(cdev->cdev);
+ kfree(cdev);
+ kobject_put(parent);
+}
+
+static void
+linux_cdev_static_release(struct kobject *kobj)
+{
+ struct linux_cdev *cdev;
+ struct kobject *parent;
+
+ cdev = container_of(kobj, struct linux_cdev, kobj);
+ parent = kobj->parent;
+ if (cdev->cdev)
+ destroy_dev(cdev->cdev);
+ kobject_put(parent);
+}
+
+const struct kobj_type linux_cdev_ktype = {
+ .release = linux_cdev_release,
+};
+
+const struct kobj_type linux_cdev_static_ktype = {
+ .release = linux_cdev_static_release,
+};
+
+static void
linux_compat_init(void *arg)
{
struct sysctl_oid *rootoid;
@@ -1009,18 +1144,18 @@ linux_compat_init(void *arg)
rootoid = SYSCTL_ADD_ROOT_NODE(NULL,
OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys");
- kobject_init(&class_root, &class_ktype);
- kobject_set_name(&class_root, "class");
- class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
+ kobject_init(&linux_class_root, &linux_class_ktype);
+ kobject_set_name(&linux_class_root, "class");
+ linux_class_root.oidp = SYSCTL_ADD_NODE(NULL, SYSCTL_CHILDREN(rootoid),
OID_AUTO, "class", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "class");
- kobject_init(&linux_rootdev.kobj, &dev_ktype);
- kobject_set_name(&linux_rootdev.kobj, "device");
- linux_rootdev.kobj.oidp = SYSCTL_ADD_NODE(NULL,
+ kobject_init(&linux_root_device.kobj, &linux_dev_ktype);
+ kobject_set_name(&linux_root_device.kobj, "device");
+ linux_root_device.kobj.oidp = SYSCTL_ADD_NODE(NULL,
SYSCTL_CHILDREN(rootoid), OID_AUTO, "device", CTLFLAG_RD, NULL,
"device");
- linux_rootdev.bsddev = root_bus;
- miscclass.name = "misc";
- class_register(&miscclass);
+ linux_root_device.bsddev = root_bus;
+ linux_class_misc.name = "misc";
+ class_register(&linux_class_misc);
INIT_LIST_HEAD(&pci_drivers);
INIT_LIST_HEAD(&pci_devices);
spin_lock_init(&pci_lock);
@@ -1033,9 +1168,9 @@ SYSINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_init, NULL);
static void
linux_compat_uninit(void *arg)
{
- kobject_kfree_name(&class_root);
- kobject_kfree_name(&linux_rootdev.kobj);
- kobject_kfree_name(&miscclass.kobj);
+ linux_kobject_kfree_name(&linux_class_root);
+ linux_kobject_kfree_name(&linux_root_device.kobj);
+ linux_kobject_kfree_name(&linux_class_misc.kobj);
}
SYSUNINIT(linux_compat, SI_SUB_DRIVERS, SI_ORDER_SECOND, linux_compat_uninit, NULL);
OpenPOWER on IntegriCloud