Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5012aada authored by Stefan Achatz's avatar Stefan Achatz Committed by Jiri Kosina
Browse files

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: default avatarStefan Achatz <erazor_de@users.sourceforge.net>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent c97415a7
Loading
Loading
Loading
Loading
+127 −171
Original line number Diff line number Diff line
@@ -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 int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
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_read_settings(struct file *fp, struct kobject *kobj,
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_write_settings(struct file *fp, struct kobject *kobj,
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_read_profile5(struct file *fp, struct kobject *kobj,
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_write_profile5(struct file *fp, struct kobject *kobj,
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_actual_dpi(struct device *dev,
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_weight(struct device *dev,
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 int kone_tcu_command(struct usb_device *usb_dev, int number)
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_set_tcu(struct device *dev,
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 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
	return size;
}

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.
	 * 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 DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
	__ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
	__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.
	 * 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);
	__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.
	 * 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);
	__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
	 * 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);
	__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,
	__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
};

static struct attribute_group kone_attribute_group = {
		.attrs = kone_attributes
			kone_sysfs_set_startup_profile),
	__ATTR_NULL
};

static struct bin_attribute kone_settings_attr = {
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
};

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
	},
	__ATTR_NULL
};

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 @@ static int kone_init_specials(struct hid_device *hdev)
			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 @@ static int kone_init_specials(struct hid_device *hdev)
			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 @@ static int kone_init_specials(struct hid_device *hdev)
	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 @@ static void kone_remove_specials(struct hid_device *hdev)

	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 struct hid_driver kone_driver = {

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);
}

+74 −199

File changed.

Preview size limit exceeded, changes collapsed.

+5 −12
Original line number Diff line number Diff line
@@ -67,7 +67,6 @@ struct roccat_reader {
};

static int roccat_major;
static struct class *roccat_class;
static struct cdev roccat_cdev;

static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
@@ -289,12 +288,14 @@ EXPORT_SYMBOL_GPL(roccat_report_event);

/*
 * roccat_connect() - create a char device for special event output
 * @class: the class thats used to create the device. Meant to hold device
 * specific sysfs attributes.
 * @hid: the hid device the char device should be connected to.
 *
 * Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
 * success, a negative error code on failure.
 */
int roccat_connect(struct hid_device *hid)
int roccat_connect(struct class *klass, struct hid_device *hid)
{
	unsigned int minor;
	struct roccat_device *device;
@@ -320,7 +321,7 @@ int roccat_connect(struct hid_device *hid)
		return -EINVAL;
	}

	device->dev = device_create(roccat_class, &hid->dev,
	device->dev = device_create(klass, &hid->dev,
			MKDEV(roccat_major, minor), NULL,
			"%s%s%d", "roccat", hid->driver->name, minor);

@@ -361,7 +362,7 @@ void roccat_disconnect(int minor)

	device->exist = 0; /* TODO exist maybe not needed */

	device_destroy(roccat_class, MKDEV(roccat_major, minor));
	device_destroy(device->dev->class, MKDEV(roccat_major, minor));

	if (device->open) {
		hid_hw_close(device->hid);
@@ -396,13 +397,6 @@ static int __init roccat_init(void)
		return retval;
	}

	roccat_class = class_create(THIS_MODULE, "roccat");
	if (IS_ERR(roccat_class)) {
		retval = PTR_ERR(roccat_class);
		unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
		return retval;
	}

	cdev_init(&roccat_cdev, &roccat_ops);
	cdev_add(&roccat_cdev, dev_id, ROCCAT_MAX_DEVICES);

@@ -414,7 +408,6 @@ static void __exit roccat_exit(void)
	dev_t dev_id = MKDEV(roccat_major, 0);

	cdev_del(&roccat_cdev);
	class_destroy(roccat_class);
	unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
}

+3 −2
Original line number Diff line number Diff line
@@ -16,11 +16,12 @@
#include <linux/types.h>

#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
int roccat_connect(struct hid_device *hid);
int roccat_connect(struct class *klass, struct hid_device *hid);
void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data, int len);
#else
static inline int roccat_connect(struct hid_device *hid) { return -1; }
static inline int roccat_connect(struct class *klass,
		struct hid_device *hid) { return -1; }
static inline void roccat_disconnect(int minor) {}
static inline int roccat_report_event(int minor, u8 const *data, int len)
{