Loading Documentation/ABI/testing/sysfs-driver-hid-roccat-kone +0 −13 Original line number Diff line number Diff line Loading @@ -33,19 +33,6 @@ Description: When read, this file returns the raw integer version number of the left. E.g. a returned value of 138 means 1.38 This file is readonly. What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version Date: March 2010 Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Description: When read, this file returns the driver version. The format of the string is "v<major>.<minor>.<patchlevel>". This attribute is used by the userland tools to find the sysfs- paths of installed kone-mice and determine the capabilites of the driver. Versions of this driver for old kernels replace usbhid instead of generic-usb. The way to scan for this file has been chosen to provide a consistent way for all supported kernel versions. This file is readonly. What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5] Date: March 2010 Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Loading drivers/hid/hid-core.c +2 −0 Original line number Diff line number Diff line Loading @@ -1157,6 +1157,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE) connect_mask |= HID_CONNECT_HIDINPUT_FORCE; if (hdev->bus != BUS_USB) connect_mask &= ~HID_CONNECT_HIDDEV; if (hid_hiddev(hdev)) Loading drivers/hid/hid-ids.h +3 −1 Original line number Diff line number Diff line Loading @@ -439,6 +439,9 @@ #define USB_VENDOR_ID_PHILIPS 0x0471 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 #define USB_VENDOR_ID_PI_ENGINEERING 0x05f3 #define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 Loading Loading @@ -533,5 +536,4 @@ #define USB_VENDOR_ID_ZYDACRON 0x13EC #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 #endif drivers/hid/hid-magicmouse.c +73 −23 Original line number Diff line number Diff line Loading @@ -30,6 +30,21 @@ static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); static unsigned int scroll_speed = 32; static int param_set_scroll_speed(const char *val, struct kernel_param *kp) { unsigned long speed; if (!val || strict_strtoul(val, 0, &speed) || speed > 63) return -EINVAL; scroll_speed = speed; return 0; } module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644); MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)"); static bool scroll_acceleration = false; module_param(scroll_acceleration, bool, 0644); MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); Loading @@ -50,6 +65,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TOUCH_STATE_START 0x30 #define TOUCH_STATE_DRAG 0x40 #define SCROLL_ACCEL_DEFAULT 7 /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. Loading Loading @@ -78,8 +95,10 @@ struct magicmouse_sc { struct { short x; short y; short scroll_x; short scroll_y; u8 size; u8 down; } touches[16]; int tracking_ids[16]; }; Loading Loading @@ -141,7 +160,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) input_report_key(msc->input, BTN_RIGHT, state & 2); if (state != last_state) msc->scroll_accel = 0; msc->scroll_accel = SCROLL_ACCEL_DEFAULT; } static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) Loading @@ -152,6 +171,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda int id = (misc >> 6) & 15; int x = x_y << 12 >> 20; int y = -(x_y >> 20); int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE; /* Store tracking ID and other fields. */ msc->tracking_ids[raw_id] = id; Loading @@ -160,42 +180,54 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda msc->touches[id].size = misc & 63; /* If requested, emulate a scroll wheel by detecting small * vertical touch motions along the middle of the mouse. * vertical touch motions. */ if (emulate_scroll_wheel && middle_button_start < x && x < middle_button_stop) { static const int accel_profile[] = { 256, 228, 192, 160, 128, 96, 64, 32, }; if (emulate_scroll_wheel) { unsigned long now = jiffies; int step = msc->touches[id].scroll_y - y; /* Reset acceleration after half a second. */ if (time_after(now, msc->scroll_jiffies + HZ / 2)) msc->scroll_accel = 0; int step_x = msc->touches[id].scroll_x - x; int step_y = msc->touches[id].scroll_y - y; /* Calculate and apply the scroll motion. */ switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_x = x; msc->touches[id].scroll_y = y; msc->scroll_accel = min_t(int, msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); /* Reset acceleration after half a second. */ if (scroll_acceleration && time_before(now, msc->scroll_jiffies + HZ / 2)) msc->scroll_accel = max_t(int, msc->scroll_accel - 1, 1); else msc->scroll_accel = SCROLL_ACCEL_DEFAULT; break; case TOUCH_STATE_DRAG: step = step / accel_profile[msc->scroll_accel]; if (step != 0) { msc->touches[id].scroll_y = y; step_x /= (64 - (int)scroll_speed) * msc->scroll_accel; if (step_x != 0) { msc->touches[id].scroll_x -= step_x * (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; input_report_rel(input, REL_HWHEEL, -step_x); } step_y /= (64 - (int)scroll_speed) * msc->scroll_accel; if (step_y != 0) { msc->touches[id].scroll_y -= step_y * (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; input_report_rel(input, REL_WHEEL, step); input_report_rel(input, REL_WHEEL, step_y); } break; } } /* Generate the input events for this touch. */ if (report_touches) { if (report_touches && down) { int orientation = (misc >> 10) - 32; msc->touches[id].down = 1; input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); Loading @@ -215,7 +247,7 @@ static int magicmouse_raw_event(struct hid_device *hdev, { struct magicmouse_sc *msc = hid_get_drvdata(hdev); struct input_dev *input = msc->input; int x, y, ts, ii, clicks; int x, y, ts, ii, clicks, last_up; switch (data[0]) { case 0x10: Loading @@ -235,12 +267,26 @@ static int magicmouse_raw_event(struct hid_device *hdev, msc->ntouches = (size - 6) / 8; for (ii = 0; ii < msc->ntouches; ii++) magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); if (report_touches) { last_up = 1; for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) { if (msc->touches[ii].down) { last_up = 0; msc->touches[ii].down = 0; } } if (last_up) { input_mt_sync(input); } } /* When emulating three-button mode, it is important * to have the current touch information before * generating a click event. */ x = (signed char)data[1]; y = (signed char)data[2]; x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22; y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22; clicks = data[3]; break; case 0x20: /* Theoretically battery status (0-100), but I have Loading Loading @@ -301,8 +347,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h __set_bit(EV_REL, input->evbit); __set_bit(REL_X, input->relbit); __set_bit(REL_Y, input->relbit); if (emulate_scroll_wheel) if (emulate_scroll_wheel) { __set_bit(REL_WHEEL, input->relbit); __set_bit(REL_HWHEEL, input->relbit); } if (report_touches) { __set_bit(EV_ABS, input->evbit); Loading Loading @@ -345,6 +393,8 @@ static int magicmouse_probe(struct hid_device *hdev, return -ENOMEM; } msc->scroll_accel = SCROLL_ACCEL_DEFAULT; msc->quirks = id->driver_data; hid_set_drvdata(hdev, msc); Loading drivers/hid/hid-roccat-kone.c +2 −23 Original line number Diff line number Diff line Loading @@ -22,11 +22,6 @@ * Is it possible to remove and reinstall the urb in raw-event- or any * other handler, or to defer this action to be executed somewhere else? * * TODO implement notification mechanism for overlong macro execution * If user wants to execute an overlong macro only the names of macroset * and macro are given. Should userland tap hidraw or is there an * additional streaming mechanism? * * TODO is it possible to overwrite group for sysfs attributes via udev? */ Loading Loading @@ -277,7 +272,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, count = sizeof(struct kone_settings) - off; mutex_lock(&kone->kone_lock); memcpy(buf, &kone->settings + off, count); memcpy(buf, ((char const *)&kone->settings) + off, count); mutex_unlock(&kone->kone_lock); return count; Loading Loading @@ -337,7 +332,7 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, count = sizeof(struct kone_profile) - off; mutex_lock(&kone->kone_lock); memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile)); memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count); mutex_unlock(&kone->kone_lock); return count; Loading Loading @@ -622,18 +617,6 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, return size; } /* * This file is used by userland software to find devices that are handled by * this driver. This provides a consistent way for actual and older kernels * where this driver replaced usbhid instead of generic-usb. * Driver capabilities are determined by version number. */ static ssize_t kone_sysfs_show_driver_version(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n"); } /* * Read actual dpi settings. * Returns raw value for further processing. Refer to enum kone_polling_rates to Loading Loading @@ -671,9 +654,6 @@ static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile, kone_sysfs_set_startup_profile); static DEVICE_ATTR(kone_driver_version, 0440, kone_sysfs_show_driver_version, NULL); static struct attribute *kone_attributes[] = { &dev_attr_actual_dpi.attr, &dev_attr_actual_profile.attr, Loading @@ -681,7 +661,6 @@ static struct attribute *kone_attributes[] = { &dev_attr_firmware_version.attr, &dev_attr_tcu.attr, &dev_attr_startup_profile.attr, &dev_attr_kone_driver_version.attr, NULL }; Loading Loading
Documentation/ABI/testing/sysfs-driver-hid-roccat-kone +0 −13 Original line number Diff line number Diff line Loading @@ -33,19 +33,6 @@ Description: When read, this file returns the raw integer version number of the left. E.g. a returned value of 138 means 1.38 This file is readonly. What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version Date: March 2010 Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Description: When read, this file returns the driver version. The format of the string is "v<major>.<minor>.<patchlevel>". This attribute is used by the userland tools to find the sysfs- paths of installed kone-mice and determine the capabilites of the driver. Versions of this driver for old kernels replace usbhid instead of generic-usb. The way to scan for this file has been chosen to provide a consistent way for all supported kernel versions. This file is readonly. What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5] Date: March 2010 Contact: Stefan Achatz <erazor_de@users.sourceforge.net> Loading
drivers/hid/hid-core.c +2 −0 Original line number Diff line number Diff line Loading @@ -1157,6 +1157,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE) connect_mask |= HID_CONNECT_HIDINPUT_FORCE; if (hdev->bus != BUS_USB) connect_mask &= ~HID_CONNECT_HIDDEV; if (hid_hiddev(hdev)) Loading
drivers/hid/hid-ids.h +3 −1 Original line number Diff line number Diff line Loading @@ -439,6 +439,9 @@ #define USB_VENDOR_ID_PHILIPS 0x0471 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 #define USB_VENDOR_ID_PI_ENGINEERING 0x05f3 #define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 Loading Loading @@ -533,5 +536,4 @@ #define USB_VENDOR_ID_ZYDACRON 0x13EC #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 #endif
drivers/hid/hid-magicmouse.c +73 −23 Original line number Diff line number Diff line Loading @@ -30,6 +30,21 @@ static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); static unsigned int scroll_speed = 32; static int param_set_scroll_speed(const char *val, struct kernel_param *kp) { unsigned long speed; if (!val || strict_strtoul(val, 0, &speed) || speed > 63) return -EINVAL; scroll_speed = speed; return 0; } module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644); MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)"); static bool scroll_acceleration = false; module_param(scroll_acceleration, bool, 0644); MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); Loading @@ -50,6 +65,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TOUCH_STATE_START 0x30 #define TOUCH_STATE_DRAG 0x40 #define SCROLL_ACCEL_DEFAULT 7 /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. Loading Loading @@ -78,8 +95,10 @@ struct magicmouse_sc { struct { short x; short y; short scroll_x; short scroll_y; u8 size; u8 down; } touches[16]; int tracking_ids[16]; }; Loading Loading @@ -141,7 +160,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) input_report_key(msc->input, BTN_RIGHT, state & 2); if (state != last_state) msc->scroll_accel = 0; msc->scroll_accel = SCROLL_ACCEL_DEFAULT; } static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) Loading @@ -152,6 +171,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda int id = (misc >> 6) & 15; int x = x_y << 12 >> 20; int y = -(x_y >> 20); int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE; /* Store tracking ID and other fields. */ msc->tracking_ids[raw_id] = id; Loading @@ -160,42 +180,54 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda msc->touches[id].size = misc & 63; /* If requested, emulate a scroll wheel by detecting small * vertical touch motions along the middle of the mouse. * vertical touch motions. */ if (emulate_scroll_wheel && middle_button_start < x && x < middle_button_stop) { static const int accel_profile[] = { 256, 228, 192, 160, 128, 96, 64, 32, }; if (emulate_scroll_wheel) { unsigned long now = jiffies; int step = msc->touches[id].scroll_y - y; /* Reset acceleration after half a second. */ if (time_after(now, msc->scroll_jiffies + HZ / 2)) msc->scroll_accel = 0; int step_x = msc->touches[id].scroll_x - x; int step_y = msc->touches[id].scroll_y - y; /* Calculate and apply the scroll motion. */ switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_x = x; msc->touches[id].scroll_y = y; msc->scroll_accel = min_t(int, msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); /* Reset acceleration after half a second. */ if (scroll_acceleration && time_before(now, msc->scroll_jiffies + HZ / 2)) msc->scroll_accel = max_t(int, msc->scroll_accel - 1, 1); else msc->scroll_accel = SCROLL_ACCEL_DEFAULT; break; case TOUCH_STATE_DRAG: step = step / accel_profile[msc->scroll_accel]; if (step != 0) { msc->touches[id].scroll_y = y; step_x /= (64 - (int)scroll_speed) * msc->scroll_accel; if (step_x != 0) { msc->touches[id].scroll_x -= step_x * (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; input_report_rel(input, REL_HWHEEL, -step_x); } step_y /= (64 - (int)scroll_speed) * msc->scroll_accel; if (step_y != 0) { msc->touches[id].scroll_y -= step_y * (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; input_report_rel(input, REL_WHEEL, step); input_report_rel(input, REL_WHEEL, step_y); } break; } } /* Generate the input events for this touch. */ if (report_touches) { if (report_touches && down) { int orientation = (misc >> 10) - 32; msc->touches[id].down = 1; input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); Loading @@ -215,7 +247,7 @@ static int magicmouse_raw_event(struct hid_device *hdev, { struct magicmouse_sc *msc = hid_get_drvdata(hdev); struct input_dev *input = msc->input; int x, y, ts, ii, clicks; int x, y, ts, ii, clicks, last_up; switch (data[0]) { case 0x10: Loading @@ -235,12 +267,26 @@ static int magicmouse_raw_event(struct hid_device *hdev, msc->ntouches = (size - 6) / 8; for (ii = 0; ii < msc->ntouches; ii++) magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); if (report_touches) { last_up = 1; for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) { if (msc->touches[ii].down) { last_up = 0; msc->touches[ii].down = 0; } } if (last_up) { input_mt_sync(input); } } /* When emulating three-button mode, it is important * to have the current touch information before * generating a click event. */ x = (signed char)data[1]; y = (signed char)data[2]; x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22; y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22; clicks = data[3]; break; case 0x20: /* Theoretically battery status (0-100), but I have Loading Loading @@ -301,8 +347,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h __set_bit(EV_REL, input->evbit); __set_bit(REL_X, input->relbit); __set_bit(REL_Y, input->relbit); if (emulate_scroll_wheel) if (emulate_scroll_wheel) { __set_bit(REL_WHEEL, input->relbit); __set_bit(REL_HWHEEL, input->relbit); } if (report_touches) { __set_bit(EV_ABS, input->evbit); Loading Loading @@ -345,6 +393,8 @@ static int magicmouse_probe(struct hid_device *hdev, return -ENOMEM; } msc->scroll_accel = SCROLL_ACCEL_DEFAULT; msc->quirks = id->driver_data; hid_set_drvdata(hdev, msc); Loading
drivers/hid/hid-roccat-kone.c +2 −23 Original line number Diff line number Diff line Loading @@ -22,11 +22,6 @@ * Is it possible to remove and reinstall the urb in raw-event- or any * other handler, or to defer this action to be executed somewhere else? * * TODO implement notification mechanism for overlong macro execution * If user wants to execute an overlong macro only the names of macroset * and macro are given. Should userland tap hidraw or is there an * additional streaming mechanism? * * TODO is it possible to overwrite group for sysfs attributes via udev? */ Loading Loading @@ -277,7 +272,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, count = sizeof(struct kone_settings) - off; mutex_lock(&kone->kone_lock); memcpy(buf, &kone->settings + off, count); memcpy(buf, ((char const *)&kone->settings) + off, count); mutex_unlock(&kone->kone_lock); return count; Loading Loading @@ -337,7 +332,7 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, count = sizeof(struct kone_profile) - off; mutex_lock(&kone->kone_lock); memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile)); memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count); mutex_unlock(&kone->kone_lock); return count; Loading Loading @@ -622,18 +617,6 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, return size; } /* * This file is used by userland software to find devices that are handled by * this driver. This provides a consistent way for actual and older kernels * where this driver replaced usbhid instead of generic-usb. * Driver capabilities are determined by version number. */ static ssize_t kone_sysfs_show_driver_version(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n"); } /* * Read actual dpi settings. * Returns raw value for further processing. Refer to enum kone_polling_rates to Loading Loading @@ -671,9 +654,6 @@ static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile, kone_sysfs_set_startup_profile); static DEVICE_ATTR(kone_driver_version, 0440, kone_sysfs_show_driver_version, NULL); static struct attribute *kone_attributes[] = { &dev_attr_actual_dpi.attr, &dev_attr_actual_profile.attr, Loading @@ -681,7 +661,6 @@ static struct attribute *kone_attributes[] = { &dev_attr_firmware_version.attr, &dev_attr_tcu.attr, &dev_attr_startup_profile.attr, &dev_attr_kone_driver_version.attr, NULL }; Loading