HID: roccat: use class for char device for sysfs attribute creation

Adding sysfs attributes to an already created device raises no userland
notification. Now the device drivers associate the devices attributes
with a class and use this for roccat event char device creation.

Signed-off-by: Stefan Achatz <erazor_de@users.sourceforge.net>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 73199de..648d28e 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -35,6 +35,9 @@
 #include "hid-roccat.h"
 #include "hid-roccat-kone.h"
 
+/* kone_class is used for creating sysfs attributes via roccat char device */
+static struct class *kone_class;
+
 static void kone_set_settings_checksum(struct kone_settings *settings)
 {
 	uint16_t checksum = 0;
@@ -261,7 +264,8 @@
 static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
 		struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count) {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev =
+			container_of(kobj, struct device, kobj)->parent->parent;
 	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
 	if (off >= sizeof(struct kone_settings))
@@ -285,7 +289,8 @@
 static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
 		struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count) {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev =
+			container_of(kobj, struct device, kobj)->parent->parent;
 	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 	int retval = 0, difference;
@@ -321,7 +326,8 @@
 static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
 		struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count, int number) {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev =
+			container_of(kobj, struct device, kobj)->parent->parent;
 	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 
 	if (off >= sizeof(struct kone_profile))
@@ -371,7 +377,8 @@
 static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
 		struct bin_attribute *attr, char *buf,
 		loff_t off, size_t count, int number) {
-	struct device *dev = container_of(kobj, struct device, kobj);
+	struct device *dev =
+			container_of(kobj, struct device, kobj)->parent->parent;
 	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
 	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
 	struct kone_profile *profile;
@@ -432,14 +439,16 @@
 static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+	struct kone_device *kone =
+			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
 }
 
 static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+	struct kone_device *kone =
+			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
 }
 
@@ -447,11 +456,15 @@
 static ssize_t kone_sysfs_show_weight(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	struct kone_device *kone;
+	struct usb_device *usb_dev;
 	int weight = 0;
 	int retval;
 
+	dev = dev->parent->parent;
+	kone = hid_get_drvdata(dev_get_drvdata(dev));
+	usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
 	mutex_lock(&kone->kone_lock);
 	retval = kone_get_weight(usb_dev, &weight);
 	mutex_unlock(&kone->kone_lock);
@@ -464,14 +477,16 @@
 static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+	struct kone_device *kone =
+			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
 }
 
 static ssize_t kone_sysfs_show_tcu(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+	struct kone_device *kone =
+			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu);
 }
 
@@ -503,11 +518,15 @@
 static ssize_t kone_sysfs_set_tcu(struct device *dev,
 		struct device_attribute *attr, char const *buf, size_t size)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	struct kone_device *kone;
+	struct usb_device *usb_dev;
 	int retval;
 	unsigned long state;
 
+	dev = dev->parent->parent;
+	kone = hid_get_drvdata(dev_get_drvdata(dev));
+	usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
 	retval = strict_strtoul(buf, 10, &state);
 	if (retval)
 		return retval;
@@ -578,18 +597,23 @@
 static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+	struct kone_device *kone =
+			hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
 	return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile);
 }
 
 static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
 		struct device_attribute *attr, char const *buf, size_t size)
 {
-	struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
-	struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+	struct kone_device *kone;
+	struct usb_device *usb_dev;
 	int retval;
 	unsigned long new_startup_profile;
 
+	dev = dev->parent->parent;
+	kone = hid_get_drvdata(dev_get_drvdata(dev));
+	usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
 	retval = strict_strtoul(buf, 10, &new_startup_profile);
 	if (retval)
 		return retval;
@@ -616,160 +640,87 @@
 	return size;
 }
 
-/*
- * Read actual dpi settings.
- * Returns raw value for further processing. Refer to enum kone_polling_rates to
- * get real value.
- */
-static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
+static struct device_attribute kone_attributes[] = {
+	/*
+	 * Read actual dpi settings.
+	 * Returns raw value for further processing. Refer to enum
+	 * kone_polling_rates to get real value.
+	 */
+	__ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
+	__ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
 
-static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
+	/*
+	 * The mouse can be equipped with one of four supplied weights from 5
+	 * to 20 grams which are recognized and its value can be read out.
+	 * This returns the raw value reported by the mouse for easy evaluation
+	 * by software. Refer to enum kone_weights to get corresponding real
+	 * weight.
+	 */
+	__ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
 
-/*
- * The mouse can be equipped with one of four supplied weights from 5 to 20
- * grams which are recognized and its value can be read out.
- * This returns the raw value reported by the mouse for easy evaluation by
- * software. Refer to enum kone_weights to get corresponding real weight.
- */
-static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
+	/*
+	 * Prints firmware version stored in mouse as integer.
+	 * The raw value reported by the mouse is returned for easy evaluation,
+	 * to get the real version number the decimal point has to be shifted 2
+	 * positions to the left. E.g. a value of 138 means 1.38.
+	 */
+	__ATTR(firmware_version, 0440,
+			kone_sysfs_show_firmware_version, NULL),
 
-/*
- * Prints firmware version stored in mouse as integer.
- * The raw value reported by the mouse is returned for easy evaluation, to get
- * the real version number the decimal point has to be shifted 2 positions to
- * the left. E.g. a value of 138 means 1.38.
- */
-static DEVICE_ATTR(firmware_version, 0440,
-		kone_sysfs_show_firmware_version, NULL);
+	/*
+	 * Prints state of Tracking Control Unit as number where 0 = off and
+	 * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
+	 * activates the tcu
+	 */
+	__ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
 
-/*
- * Prints state of Tracking Control Unit as number where 0 = off and 1 = on
- * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu
- */
-static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
-
-/* Prints and takes the number of the profile the mouse starts with */
-static DEVICE_ATTR(startup_profile, 0660,
-		kone_sysfs_show_startup_profile,
-		kone_sysfs_set_startup_profile);
-
-static struct attribute *kone_attributes[] = {
-		&dev_attr_actual_dpi.attr,
-		&dev_attr_actual_profile.attr,
-		&dev_attr_weight.attr,
-		&dev_attr_firmware_version.attr,
-		&dev_attr_tcu.attr,
-		&dev_attr_startup_profile.attr,
-		NULL
+	/* Prints and takes the number of the profile the mouse starts with */
+	__ATTR(startup_profile, 0660,
+			kone_sysfs_show_startup_profile,
+			kone_sysfs_set_startup_profile),
+	__ATTR_NULL
 };
 
-static struct attribute_group kone_attribute_group = {
-		.attrs = kone_attributes
+static struct bin_attribute kone_bin_attributes[] = {
+	{
+		.attr = { .name = "settings", .mode = 0660 },
+		.size = sizeof(struct kone_settings),
+		.read = kone_sysfs_read_settings,
+		.write = kone_sysfs_write_settings
+	},
+	{
+		.attr = { .name = "profile1", .mode = 0660 },
+		.size = sizeof(struct kone_profile),
+		.read = kone_sysfs_read_profile1,
+		.write = kone_sysfs_write_profile1
+	},
+	{
+		.attr = { .name = "profile2", .mode = 0660 },
+		.size = sizeof(struct kone_profile),
+		.read = kone_sysfs_read_profile2,
+		.write = kone_sysfs_write_profile2
+	},
+	{
+		.attr = { .name = "profile3", .mode = 0660 },
+		.size = sizeof(struct kone_profile),
+		.read = kone_sysfs_read_profile3,
+		.write = kone_sysfs_write_profile3
+	},
+	{
+		.attr = { .name = "profile4", .mode = 0660 },
+		.size = sizeof(struct kone_profile),
+		.read = kone_sysfs_read_profile4,
+		.write = kone_sysfs_write_profile4
+	},
+	{
+		.attr = { .name = "profile5", .mode = 0660 },
+		.size = sizeof(struct kone_profile),
+		.read = kone_sysfs_read_profile5,
+		.write = kone_sysfs_write_profile5
+	},
+	__ATTR_NULL
 };
 
-static struct bin_attribute kone_settings_attr = {
-	.attr = { .name = "settings", .mode = 0660 },
-	.size = sizeof(struct kone_settings),
-	.read = kone_sysfs_read_settings,
-	.write = kone_sysfs_write_settings
-};
-
-static struct bin_attribute kone_profile1_attr = {
-	.attr = { .name = "profile1", .mode = 0660 },
-	.size = sizeof(struct kone_profile),
-	.read = kone_sysfs_read_profile1,
-	.write = kone_sysfs_write_profile1
-};
-
-static struct bin_attribute kone_profile2_attr = {
-	.attr = { .name = "profile2", .mode = 0660 },
-	.size = sizeof(struct kone_profile),
-	.read = kone_sysfs_read_profile2,
-	.write = kone_sysfs_write_profile2
-};
-
-static struct bin_attribute kone_profile3_attr = {
-	.attr = { .name = "profile3", .mode = 0660 },
-	.size = sizeof(struct kone_profile),
-	.read = kone_sysfs_read_profile3,
-	.write = kone_sysfs_write_profile3
-};
-
-static struct bin_attribute kone_profile4_attr = {
-	.attr = { .name = "profile4", .mode = 0660 },
-	.size = sizeof(struct kone_profile),
-	.read = kone_sysfs_read_profile4,
-	.write = kone_sysfs_write_profile4
-};
-
-static struct bin_attribute kone_profile5_attr = {
-	.attr = { .name = "profile5", .mode = 0660 },
-	.size = sizeof(struct kone_profile),
-	.read = kone_sysfs_read_profile5,
-	.write = kone_sysfs_write_profile5
-};
-
-static int kone_create_sysfs_attributes(struct usb_interface *intf)
-{
-	int retval;
-
-	retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group);
-	if (retval)
-		goto exit_1;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr);
-	if (retval)
-		goto exit_2;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-	if (retval)
-		goto exit_3;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-	if (retval)
-		goto exit_4;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-	if (retval)
-		goto exit_5;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-	if (retval)
-		goto exit_6;
-
-	retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr);
-	if (retval)
-		goto exit_7;
-
-	return 0;
-
-exit_7:
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-exit_6:
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-exit_5:
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-exit_4:
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-exit_3:
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-exit_2:
-	sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-exit_1:
-	return retval;
-}
-
-static void kone_remove_sysfs_attributes(struct usb_interface *intf)
-{
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr);
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-	sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-	sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-}
-
 static int kone_init_kone_device_struct(struct usb_device *usb_dev,
 		struct kone_device *kone)
 {
@@ -828,7 +779,7 @@
 			goto exit_free;
 		}
 
-		retval = roccat_connect(hdev);
+		retval = roccat_connect(kone_class, hdev);
 		if (retval < 0) {
 			hid_err(hdev, "couldn't init char dev\n");
 			/* be tolerant about not getting chrdev */
@@ -836,12 +787,6 @@
 			kone->roccat_claimed = 1;
 			kone->chrdev_minor = retval;
 		}
-
-		retval = kone_create_sysfs_attributes(intf);
-		if (retval) {
-			hid_err(hdev, "cannot create sysfs files\n");
-			goto exit_free;
-		}
 	} else {
 		hid_set_drvdata(hdev, NULL);
 	}
@@ -852,7 +797,6 @@
 	return retval;
 }
 
-
 static void kone_remove_specials(struct hid_device *hdev)
 {
 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
@@ -860,7 +804,6 @@
 
 	if (intf->cur_altsetting->desc.bInterfaceProtocol
 			== USB_INTERFACE_PROTOCOL_MOUSE) {
-		kone_remove_sysfs_attributes(intf);
 		kone = hid_get_drvdata(hdev);
 		if (kone->roccat_claimed)
 			roccat_disconnect(kone->chrdev_minor);
@@ -1004,11 +947,24 @@
 
 static int __init kone_init(void)
 {
-	return hid_register_driver(&kone_driver);
+	int retval;
+
+	/* class name has to be same as driver name */
+	kone_class = class_create(THIS_MODULE, "kone");
+	if (IS_ERR(kone_class))
+		return PTR_ERR(kone_class);
+	kone_class->dev_attrs = kone_attributes;
+	kone_class->dev_bin_attrs = kone_bin_attributes;
+
+	retval = hid_register_driver(&kone_driver);
+	if (retval)
+		class_destroy(kone_class);
+	return retval;
 }
 
 static void __exit kone_exit(void)
 {
+	class_destroy(kone_class);
 	hid_unregister_driver(&kone_driver);
 }