Signed-off-by: Jaap Aarts <jaap.aarts1@xxxxxxxxxxx> --- ...driver.patch.EXPERIMENTAL-checkpatch-fixes | 239 ++++++++++++++++++ drivers/hwmon/asetek_gen6.c | 31 ++- 2 files changed, 260 insertions(+), 10 deletions(-) create mode 100644 0001-skeleton-for-asetek-gen-6-driver.patch.EXPERIMENTAL-checkpatch-fixes diff --git a/0001-skeleton-for-asetek-gen-6-driver.patch.EXPERIMENTAL-checkpatch-fixes b/0001-skeleton-for-asetek-gen-6-driver.patch.EXPERIMENTAL-checkpatch-fixes new file mode 100644 index 000000000000..6f47a064072b --- /dev/null +++ b/0001-skeleton-for-asetek-gen-6-driver.patch.EXPERIMENTAL-checkpatch-fixes @@ -0,0 +1,239 @@ +From 84c7d189d0f4227f7b249a73c2c1bd26ed4f46a6 Mon Sep 17 00:00:00 2001 +From: jaap aarts <jaap.aarts1@xxxxxxxxx> +Date: Tue, 30 Jun 2020 13:46:14 +0200 +Subject: [PATCH 1/5] skeleton for asetek gen 6 driver + +--- + drivers/hwmon/Kconfig | 6 ++ + drivers/hwmon/Makefile | 1 + + drivers/hwmon/asetek_gen6.c | 186 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 193 insertions(+) + create mode 100644 drivers/hwmon/asetek_gen6.c + +diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig +index 288ae9f63588..521a9e0c88ca 100644 +--- a/drivers/hwmon/Kconfig ++++ b/drivers/hwmon/Kconfig +@@ -378,6 +378,12 @@ config SENSORS_ARM_SCPI + and power sensors available on ARM Ltd's SCP based platforms. The + actual number and type of sensors exported depend on the platform. + ++config SENSORS_ASETEK_GEN6 ++ tristate "Asetek generation 6 driver" ++ help ++ If you say yes here you get support for asetek generation 6 boards ++ found on most AIO liquid coolers with an asetek pump. ++ + config SENSORS_ASB100 + tristate "Asus ASB100 Bach" + depends on X86 && I2C +diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile +index 3e32c21f5efe..9683d2aae2b2 100644 +--- a/drivers/hwmon/Makefile ++++ b/drivers/hwmon/Makefile +@@ -20,6 +20,7 @@ obj-$(CONFIG_SENSORS_W83793) += w83793.o + obj-$(CONFIG_SENSORS_W83795) += w83795.o + obj-$(CONFIG_SENSORS_W83781D) += w83781d.o + obj-$(CONFIG_SENSORS_W83791D) += w83791d.o ++obj-$(CONFIG_SENSORS_ASETEK_GEN6) += asetek_gen6.o + + obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o + obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o +diff --git a/drivers/hwmon/asetek_gen6.c b/drivers/hwmon/asetek_gen6.c +new file mode 100644 +index 000000000000..4d530a4cb71d +--- /dev/null ++++ b/drivers/hwmon/asetek_gen6.c +@@ -0,0 +4,189 @@ ++// SPDX-License-Identifier: GPL-2.0-or-later ++/* ++ * A hwmon driver for most asetek gen 6 all-in-one liquid coolers. ++ * Copyright (c) Jaap Aarts 2020 ++ * ++ * Protocol reverse engineered by audiohacked ++ * https://github.com/audiohacked/OpenCorsairLink ++ */ ++ ++/* ++ * Supports following chips: ++ * driver h100i platinum ++ * ++ * Other products should work with this driver but no testing has been done. ++ * ++ * Note: platinum is the codename name for pro within driver ++ * ++ * Note: fan curve control has not been implemented ++ */ ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/usb.h> ++#include <linux/slab.h> ++#include <linux/mutex.h> ++#include <linux/errno.h> ++#include <linux/hwmon.h> ++#include <linux/hwmon-sysfs.h> ++ ++struct driver { ++ struct usb_device *udev; ++ ++ char *bulk_out_buffer; ++ char *bulk_in_buffer; ++ size_t bulk_out_size; ++ size_t bulk_in_size; ++ char bulk_in_endpointAddr; ++ char bulk_out_endpointAddr; ++ ++ struct usb_interface *interface; /* the interface for this device */ ++ struct mutex io_mutex; /* synchronize I/O with disconnect */ ++ struct semaphore ++ limit_sem; /* limiting the number of writes in progress */ ++ ++ struct kref kref; ++}; ++ ++/* devices that work with this driver */ ++static const struct usb_device_id astk_table[] = { ++ { USB_DEVICE(0x1b1c, 0x0c15) }, ++ {} /* Terminating entry */ ++}; ++ ++MODULE_DEVICE_TABLE(usb, astk_table); ++ ++int init_device(struct usb_device *udev) ++{ ++ int retval; ++ ++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, 0x40, ++ 0xffff, 0x0000, 0, 0, 0); ++ //this always returns error ++ if (retval != 0) ++ ; ++ ++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x02, 0x40, ++ 0x0002, 0x0000, 0, 0, 0); ++ if (retval != 0) ++ return retval; ++ ++ return 0; ++} ++int deinit_device(struct usb_device *udev) ++{ ++ int retval; ++ ++ retval = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x02, 0x40, ++ 0x0004, 0x0000, 0, 0, 0); ++ if (retval != 0) ++ return retval; ++ ++ return 0; ++} ++ ++static void astk_delete(struct kref *kref) ++{ ++ struct driver *dev = container_of(kref, struct driver, kref); ++ ++ usb_put_intf(dev->interface); ++ usb_put_dev(dev->udev); ++ kfree(dev->bulk_in_buffer); ++ kfree(dev->bulk_out_buffer); ++ kfree(dev); ++} ++ ++static int astk_probe(struct usb_interface *interface, ++ const struct usb_device_id *id) ++{ ++ struct driver *dev; ++ int retval = 0; ++ struct usb_endpoint_descriptor *bulk_in, *bulk_out; ++ ++ dev = kzalloc(sizeof(*dev), GFP_KERNEL); ++ if (!dev) { ++ retval = -ENOMEM; ++ goto exit; ++ } ++ ++ retval = usb_find_common_endpoints(interface->cur_altsetting, &bulk_in, ++ &bulk_out, NULL, NULL); ++ if (retval != 0) ++ goto exit; ++ ++ dev->udev = usb_get_dev(interface_to_usbdev(interface)); ++ dev->interface = usb_get_intf(interface); ++ ++ /* set up the endpoint information */ ++ /* use only the first bulk-in and bulk-out endpoints */ ++ dev->bulk_in_size = usb_endpoint_maxp(bulk_in); ++ dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL); ++ dev->bulk_in_endpointAddr = bulk_in->bEndpointAddress; ++ dev->bulk_out_size = usb_endpoint_maxp(bulk_out); ++ dev->bulk_out_buffer = kmalloc(dev->bulk_out_size, GFP_KERNEL); ++ dev->bulk_out_endpointAddr = bulk_out->bEndpointAddress; ++ ++ //hwmon_init(dev); ++ retval = init_device(dev->udev); ++ if (retval) { ++ dev_err(&interface->dev, "Failled initialising this device.\n"); ++ goto exit; ++ } ++ ++ usb_set_intfdata(interface, dev); ++ kref_init(&dev->kref); ++ mutex_init(&dev->io_mutex); ++ sema_init(&dev->limit_sem, 8); ++exit: ++ return retval; ++} ++ ++static void astk_disconnect(struct usb_interface *interface) ++{ ++ struct driver *dev = usb_get_intfdata(interface); ++ //hwmon_deinit(dev); ++ usb_set_intfdata(interface, NULL); ++ kref_put(&dev->kref, astk_delete); ++ deinit_device(dev->udev); ++ /* let the user know what node this device is now attached to */ ++} ++static int astk_resume(struct usb_interface *intf) ++{ ++ return 0; ++} ++ ++static int astk_suspend(struct usb_interface *intf, pm_message_t message) ++{ ++ return 0; ++} ++ ++static struct usb_driver astk_driver = { ++ .name = "Asetek gen6 driver", ++ .id_table = astk_table, ++ .probe = astk_probe, ++ .disconnect = astk_disconnect, ++ .resume = astk_resume, ++ .suspend = astk_suspend, ++ .supports_autosuspend = 1, ++}; ++ ++static int __init astk_init(void) ++{ ++ int ret = -1; ++ ++ ret = usb_register(&astk_driver); ++ ++ return ret; ++} ++ ++static void __exit astk_exit(void) ++{ ++ usb_deregister(&astk_driver); ++} ++ ++module_init(astk_init); ++module_exit(astk_exit); ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Jaap Aarts <jaap.aarts1@xxxxxxxxx>"); ++MODULE_DESCRIPTION("Asetek gen6 driver"); +-- +2.27.0 + diff --git a/drivers/hwmon/asetek_gen6.c b/drivers/hwmon/asetek_gen6.c index 19f50d5cd179..7fc31d4b5743 100644 --- a/drivers/hwmon/asetek_gen6.c +++ b/drivers/hwmon/asetek_gen6.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* +/* * A hwmon driver for most asetek gen 6 all-in-one liquid coolers. * Copyright (c) Jaap Aarts 2020 * @@ -15,7 +15,7 @@ * * Note: platinum is the codename name for pro within driver, so h100i platinum = h1ooi pro * - * Note: fan curve controll has not been implemented + * Note: fan curve control has not been implemented */ #include <linux/module.h> @@ -158,6 +158,7 @@ struct curve_point extreme_curve[] = { }; #define default_curve quiet_curve + static const char SUCCESS[2] = { 0x12, 0x34 }; #define SUCCES_LENGTH 3 @@ -211,6 +212,7 @@ int set_fan_rpm_curve(struct driver *cdev, struct hwmon_fan_data *fan_data, recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]); return 0; } + int set_fan_target_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data, long val) { @@ -244,10 +246,12 @@ int set_fan_target_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data, recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]); return 0; } + void get_fan_target_rpm(struct hwmon_fan_data *fan_data, long *val) { *val = fan_data->fan_target; } + int get_fan_current_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data, long *val) { @@ -272,7 +276,7 @@ int get_fan_current_rpm(struct driver *cdev, struct hwmon_fan_data *fan_data, if (!check_succes(0x41, recv_buf) || recv_buf[3] != fan_data->fan_channel) - printk(KERN_INFO "[*] Failled retreiving fan rmp %d,%d,%d/%d\n", + printk(KERN_INFO "[*] Failled retrieving fan rmp %d,%d,%d/%d\n", recv_buf[0], recv_buf[1], recv_buf[2], recv_buf[3]); *val = (((uint8_t)recv_buf[4]) << 8) + (uint8_t)recv_buf[5]; @@ -470,6 +474,7 @@ static int write_func(struct device *dev, enum hwmon_sensor_types type, exit: return retval; } + int read_func(struct device *dev, enum hwmon_sensor_types type, u32 attr, int channel, long *val) { @@ -540,8 +545,9 @@ int read_func(struct device *dev, enum hwmon_sensor_types type, u32 attr, exit: return retval; } -#define fan_config HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_MIN -#define pwm_config HWMON_PWM_INPUT | HWMON_PWM_ENABLE + +#define fan_config (HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_MIN) +#define pwm_config (HWMON_PWM_INPUT | HWMON_PWM_ENABLE) static const struct hwmon_ops asetek_6_ops = { .is_visible = is_visible_func, @@ -580,8 +586,8 @@ bool does_fan_exist(struct driver *cdev, int channel) int get_fan_count(struct driver *dev) { int fan; - for (fan = 0; does_fan_exist(dev, fan); fan += 1) { - } + for (fan = 0; does_fan_exist(dev, fan); fan += 1) + ; return fan; } @@ -594,10 +600,13 @@ void hwmon_init(struct driver *dev) &dev->udev->dev, sizeof(struct hwmon_data), GFP_KERNEL); struct hwmon_chip_info *hwmon_info = devm_kzalloc( &dev->udev->dev, sizeof(struct hwmon_chip_info), GFP_KERNEL); + //Allocate the info table struct hwmon_channel_info **aio_info = devm_kzalloc(&dev->udev->dev, sizeof(struct hwmon_channel_info *) * 2, - GFP_KERNEL); //2==amount of channel infos. + GFP_KERNEL); //2 for each channel info. + + //Allocate the fan and PWM configuration u32 *fans_config = devm_kzalloc(&dev->udev->dev, sizeof(u32) * (data->channel_count + 1), GFP_KERNEL); @@ -610,6 +619,7 @@ void hwmon_init(struct driver *dev) devm_kzalloc(&dev->udev->dev, sizeof(char *) * data->channel_count, GFP_KERNEL); + //For each fan create a data channel a fan config entry and a pwm config entry for (fan_id = 0; fan_id <= data->channel_count; fan_id++) { fan = devm_kzalloc(&dev->udev->dev, sizeof(struct hwmon_fan_data), GFP_KERNEL); @@ -648,8 +658,8 @@ void hwmon_deinit(struct driver *dev) } /* - Devices that work with this driver. - More devices should work, however none have been tested. + * Devices that work with this driver. + * More devices should work, however none have been tested. */ static const struct usb_device_id astk_table[] = { { USB_DEVICE(0x1b1c, 0x0c15) }, @@ -674,6 +684,7 @@ int init_device(struct usb_device *udev) return 0; } + int deinit_device(struct usb_device *udev) { int retval; -- 2.27.0