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>
This commit is contained in:
Stefan Achatz 2010-11-26 19:57:33 +00:00 committed by Jiri Kosina
parent c97415a725
commit 5012aada50
4 changed files with 209 additions and 384 deletions

View File

@ -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 @@ exit_unlock:
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;
}
/*
* 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 @@ 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 @@ exit_free:
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);
}

View File

@ -27,6 +27,9 @@
#include "hid-roccat.h"
#include "hid-roccat-pyra.h"
/* pyra_class is used for creating sysfs attributes via roccat char device */
static struct class *pyra_class;
static void profile_activated(struct pyra_device *pyra,
unsigned int new_profile)
{
@ -222,7 +225,8 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_settings))
@ -283,7 +287,8 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_buttons))
@ -344,7 +349,8 @@ static ssize_t pyra_sysfs_write_profile_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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@ -380,7 +386,8 @@ static ssize_t pyra_sysfs_write_profile_buttons(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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@ -416,7 +423,8 @@ static ssize_t pyra_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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_settings))
@ -436,7 +444,8 @@ static ssize_t pyra_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 pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@ -468,255 +477,115 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
}
static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
}
static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
}
static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct pyra_device *pyra =
hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
}
static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
static DEVICE_ATTR(firmware_version, 0440,
pyra_sysfs_show_firmware_version, NULL);
static DEVICE_ATTR(startup_profile, 0440,
pyra_sysfs_show_startup_profile, NULL);
static struct attribute *pyra_attributes[] = {
&dev_attr_actual_cpi.attr,
&dev_attr_actual_profile.attr,
&dev_attr_firmware_version.attr,
&dev_attr_startup_profile.attr,
NULL
static struct device_attribute pyra_attributes[] = {
__ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
__ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
__ATTR(firmware_version, 0440,
pyra_sysfs_show_firmware_version, NULL),
__ATTR(startup_profile, 0440,
pyra_sysfs_show_startup_profile, NULL),
__ATTR_NULL
};
static struct attribute_group pyra_attribute_group = {
.attrs = pyra_attributes
};
static struct bin_attribute pyra_profile_settings_attr = {
static struct bin_attribute pyra_bin_attributes[] = {
{
.attr = { .name = "profile_settings", .mode = 0220 },
.size = sizeof(struct pyra_profile_settings),
.write = pyra_sysfs_write_profile_settings
};
static struct bin_attribute pyra_profile1_settings_attr = {
},
{
.attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
.read = pyra_sysfs_read_profile1_settings
};
static struct bin_attribute pyra_profile2_settings_attr = {
},
{
.attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
.read = pyra_sysfs_read_profile2_settings
};
static struct bin_attribute pyra_profile3_settings_attr = {
},
{
.attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
.read = pyra_sysfs_read_profile3_settings
};
static struct bin_attribute pyra_profile4_settings_attr = {
},
{
.attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
.read = pyra_sysfs_read_profile4_settings
};
static struct bin_attribute pyra_profile5_settings_attr = {
},
{
.attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
.read = pyra_sysfs_read_profile5_settings
};
static struct bin_attribute pyra_profile_buttons_attr = {
},
{
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct pyra_profile_buttons),
.write = pyra_sysfs_write_profile_buttons
};
static struct bin_attribute pyra_profile1_buttons_attr = {
},
{
.attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
.read = pyra_sysfs_read_profile1_buttons
};
static struct bin_attribute pyra_profile2_buttons_attr = {
},
{
.attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
.read = pyra_sysfs_read_profile2_buttons
};
static struct bin_attribute pyra_profile3_buttons_attr = {
},
{
.attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
.read = pyra_sysfs_read_profile3_buttons
};
static struct bin_attribute pyra_profile4_buttons_attr = {
},
{
.attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
.read = pyra_sysfs_read_profile4_buttons
};
static struct bin_attribute pyra_profile5_buttons_attr = {
},
{
.attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
.read = pyra_sysfs_read_profile5_buttons
};
static struct bin_attribute pyra_settings_attr = {
},
{
.attr = { .name = "settings", .mode = 0660 },
.size = sizeof(struct pyra_settings),
.read = pyra_sysfs_read_settings,
.write = pyra_sysfs_write_settings
},
__ATTR_NULL
};
static int pyra_create_sysfs_attributes(struct usb_interface *intf)
{
int retval;
retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
if (retval)
goto exit_1;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile_settings_attr);
if (retval)
goto exit_2;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile1_settings_attr);
if (retval)
goto exit_3;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile2_settings_attr);
if (retval)
goto exit_4;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile3_settings_attr);
if (retval)
goto exit_5;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile4_settings_attr);
if (retval)
goto exit_6;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile5_settings_attr);
if (retval)
goto exit_7;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile_buttons_attr);
if (retval)
goto exit_8;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile1_buttons_attr);
if (retval)
goto exit_9;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile2_buttons_attr);
if (retval)
goto exit_10;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile3_buttons_attr);
if (retval)
goto exit_11;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile4_buttons_attr);
if (retval)
goto exit_12;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_profile5_buttons_attr);
if (retval)
goto exit_13;
retval = sysfs_create_bin_file(&intf->dev.kobj,
&pyra_settings_attr);
if (retval)
goto exit_14;
return 0;
exit_14:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
exit_13:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
exit_12:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
exit_11:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
exit_10:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
exit_9:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
exit_8:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
exit_7:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
exit_6:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
exit_5:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
exit_4:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
exit_3:
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
exit_2:
sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
exit_1:
return retval;
}
static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
{
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
}
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra)
{
@ -780,19 +649,13 @@ static int pyra_init_specials(struct hid_device *hdev)
goto exit_free;
}
retval = roccat_connect(hdev);
retval = roccat_connect(pyra_class, hdev);
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
pyra->chrdev_minor = retval;
pyra->roccat_claimed = 1;
}
retval = pyra_create_sysfs_attributes(intf);
if (retval) {
hid_err(hdev, "cannot create sysfs files\n");
goto exit_free;
}
} else {
hid_set_drvdata(hdev, NULL);
}
@ -810,7 +673,6 @@ static void pyra_remove_specials(struct hid_device *hdev)
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
pyra_remove_sysfs_attributes(intf);
pyra = hid_get_drvdata(hdev);
if (pyra->roccat_claimed)
roccat_disconnect(pyra->chrdev_minor);
@ -950,11 +812,24 @@ static struct hid_driver pyra_driver = {
static int __init pyra_init(void)
{
return hid_register_driver(&pyra_driver);
int retval;
/* class name has to be same as driver name */
pyra_class = class_create(THIS_MODULE, "pyra");
if (IS_ERR(pyra_class))
return PTR_ERR(pyra_class);
pyra_class->dev_attrs = pyra_attributes;
pyra_class->dev_bin_attrs = pyra_bin_attributes;
retval = hid_register_driver(&pyra_driver);
if (retval)
class_destroy(pyra_class);
return retval;
}
static void __exit pyra_exit(void)
{
class_destroy(pyra_class);
hid_unregister_driver(&pyra_driver);
}

View File

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

View File

@ -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)
{