1*e28d0c73SAureo Serrano de Souza // SPDX-License-Identifier: GPL-2.0-or-later 2*e28d0c73SAureo Serrano de Souza /* 3*e28d0c73SAureo Serrano de Souza * Linux hwmon driver for ARCTIC Fan Controller 4*e28d0c73SAureo Serrano de Souza * 5*e28d0c73SAureo Serrano de Souza * USB Custom HID device with 10 fan channels. 6*e28d0c73SAureo Serrano de Souza * Exposes fan RPM (input) and PWM (0-255) via hwmon. Device pushes IN reports 7*e28d0c73SAureo Serrano de Souza * at ~1 Hz; no GET_REPORT. OUT reports set PWM duty (bytes 1-10, 0-100%). 8*e28d0c73SAureo Serrano de Souza * PWM is manual-only: the device does not change duty autonomously, only 9*e28d0c73SAureo Serrano de Souza * when it receives an OUT report from the host. 10*e28d0c73SAureo Serrano de Souza */ 11*e28d0c73SAureo Serrano de Souza 12*e28d0c73SAureo Serrano de Souza #include <linux/completion.h> 13*e28d0c73SAureo Serrano de Souza #include <linux/dma-mapping.h> 14*e28d0c73SAureo Serrano de Souza #include <linux/err.h> 15*e28d0c73SAureo Serrano de Souza #include <linux/hid.h> 16*e28d0c73SAureo Serrano de Souza #include <linux/hwmon.h> 17*e28d0c73SAureo Serrano de Souza #include <linux/jiffies.h> 18*e28d0c73SAureo Serrano de Souza #include <linux/minmax.h> 19*e28d0c73SAureo Serrano de Souza #include <linux/module.h> 20*e28d0c73SAureo Serrano de Souza #include <linux/spinlock.h> 21*e28d0c73SAureo Serrano de Souza #include <linux/string.h> 22*e28d0c73SAureo Serrano de Souza #include <linux/unaligned.h> 23*e28d0c73SAureo Serrano de Souza 24*e28d0c73SAureo Serrano de Souza #define ARCTIC_VID 0x3904 25*e28d0c73SAureo Serrano de Souza #define ARCTIC_PID 0xF001 26*e28d0c73SAureo Serrano de Souza #define ARCTIC_NUM_FANS 10 27*e28d0c73SAureo Serrano de Souza #define ARCTIC_OUTPUT_REPORT_ID 0x01 28*e28d0c73SAureo Serrano de Souza #define ARCTIC_REPORT_LEN 32 29*e28d0c73SAureo Serrano de Souza #define ARCTIC_RPM_OFFSET 11 /* bytes 11-30: 10 x uint16 LE */ 30*e28d0c73SAureo Serrano de Souza /* ACK report: device sends Report ID 0x02, 2 bytes (ID + status) after applying OUT report */ 31*e28d0c73SAureo Serrano de Souza #define ARCTIC_ACK_REPORT_ID 0x02 32*e28d0c73SAureo Serrano de Souza #define ARCTIC_ACK_REPORT_LEN 2 33*e28d0c73SAureo Serrano de Souza /* 34*e28d0c73SAureo Serrano de Souza * Time to wait for ACK report after send. 35*e28d0c73SAureo Serrano de Souza * Measured over 500 iterations: max ~563 ms. Keep 1 s as margin. 36*e28d0c73SAureo Serrano de Souza */ 37*e28d0c73SAureo Serrano de Souza #define ARCTIC_ACK_TIMEOUT_MS 1000 38*e28d0c73SAureo Serrano de Souza 39*e28d0c73SAureo Serrano de Souza struct arctic_fan_data { 40*e28d0c73SAureo Serrano de Souza struct hid_device *hdev; 41*e28d0c73SAureo Serrano de Souza struct device *hwmon_dev; /* stored for explicit unregister in remove() */ 42*e28d0c73SAureo Serrano de Souza spinlock_t in_report_lock; /* protects fan_rpm, ack_status, write_pending, pwm_duty */ 43*e28d0c73SAureo Serrano de Souza struct completion in_report_received; /* ACK (ID 0x02) received in raw_event */ 44*e28d0c73SAureo Serrano de Souza int ack_status; /* 0 = OK, negative errno on device error */ 45*e28d0c73SAureo Serrano de Souza bool write_pending; /* true while an OUT report ACK is in flight */ 46*e28d0c73SAureo Serrano de Souza u32 fan_rpm[ARCTIC_NUM_FANS]; 47*e28d0c73SAureo Serrano de Souza u8 pwm_duty[ARCTIC_NUM_FANS]; /* 0-255 matching sysfs range; converted to 0-100 on send */ 48*e28d0c73SAureo Serrano de Souza /* 49*e28d0c73SAureo Serrano de Souza * OUT report buffer passed to hid_hw_output_report(). Embedded in the 50*e28d0c73SAureo Serrano de Souza * devm_kzalloc'd struct so it is heap-allocated and passes 51*e28d0c73SAureo Serrano de Souza * usb_hcd_map_urb_for_dma(). Exclusively accessed by write(), which 52*e28d0c73SAureo Serrano de Souza * the hwmon core serializes. 53*e28d0c73SAureo Serrano de Souza */ 54*e28d0c73SAureo Serrano de Souza __dma_from_device_group_begin(); 55*e28d0c73SAureo Serrano de Souza u8 buf[ARCTIC_REPORT_LEN]; 56*e28d0c73SAureo Serrano de Souza __dma_from_device_group_end(); 57*e28d0c73SAureo Serrano de Souza }; 58*e28d0c73SAureo Serrano de Souza 59*e28d0c73SAureo Serrano de Souza /* 60*e28d0c73SAureo Serrano de Souza * Parse RPM values from the periodic status report (10 x uint16 LE at rpm_off). 61*e28d0c73SAureo Serrano de Souza * pwm_duty is not updated from the report: the device is manual-only, so the 62*e28d0c73SAureo Serrano de Souza * host cache is the authoritative source for PWM. 63*e28d0c73SAureo Serrano de Souza * Called from raw_event which may run in IRQ context; must not sleep. 64*e28d0c73SAureo Serrano de Souza */ 65*e28d0c73SAureo Serrano de Souza static void arctic_fan_parse_report(struct arctic_fan_data *priv, u8 *buf, 66*e28d0c73SAureo Serrano de Souza int len, int rpm_off) 67*e28d0c73SAureo Serrano de Souza { 68*e28d0c73SAureo Serrano de Souza unsigned long flags; 69*e28d0c73SAureo Serrano de Souza int i; 70*e28d0c73SAureo Serrano de Souza 71*e28d0c73SAureo Serrano de Souza if (len < rpm_off + 20) 72*e28d0c73SAureo Serrano de Souza return; 73*e28d0c73SAureo Serrano de Souza 74*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 75*e28d0c73SAureo Serrano de Souza for (i = 0; i < ARCTIC_NUM_FANS; i++) 76*e28d0c73SAureo Serrano de Souza priv->fan_rpm[i] = get_unaligned_le16(&buf[rpm_off + i * 2]); 77*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 78*e28d0c73SAureo Serrano de Souza } 79*e28d0c73SAureo Serrano de Souza 80*e28d0c73SAureo Serrano de Souza /* 81*e28d0c73SAureo Serrano de Souza * raw_event: IN reports. 82*e28d0c73SAureo Serrano de Souza * 83*e28d0c73SAureo Serrano de Souza * Status report: Report ID 0x01, 32 bytes: 84*e28d0c73SAureo Serrano de Souza * byte 0 = report ID, bytes 1-10 = PWM 0-100%, bytes 11-30 = 10 x RPM uint16 LE. 85*e28d0c73SAureo Serrano de Souza * Device pushes these at ~1 Hz; no GET_REPORT. 86*e28d0c73SAureo Serrano de Souza * 87*e28d0c73SAureo Serrano de Souza * ACK report: Report ID 0x02, 2 bytes: 88*e28d0c73SAureo Serrano de Souza * byte 0 = 0x02, byte 1 = status (0x00 = OK, 0x01 = ERROR). 89*e28d0c73SAureo Serrano de Souza * Sent once after accepting and applying an OUT report (ID 0x01). 90*e28d0c73SAureo Serrano de Souza */ 91*e28d0c73SAureo Serrano de Souza static int arctic_fan_raw_event(struct hid_device *hdev, 92*e28d0c73SAureo Serrano de Souza struct hid_report *report, u8 *data, int size) 93*e28d0c73SAureo Serrano de Souza { 94*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv = hid_get_drvdata(hdev); 95*e28d0c73SAureo Serrano de Souza unsigned long flags; 96*e28d0c73SAureo Serrano de Souza 97*e28d0c73SAureo Serrano de Souza hid_dbg(hdev, "arctic_fan: raw_event id=%u size=%d\n", report->id, size); 98*e28d0c73SAureo Serrano de Souza 99*e28d0c73SAureo Serrano de Souza if (report->id == ARCTIC_ACK_REPORT_ID && size == ARCTIC_ACK_REPORT_LEN) { 100*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 101*e28d0c73SAureo Serrano de Souza /* 102*e28d0c73SAureo Serrano de Souza * Only deliver if a write is in flight. This prevents a 103*e28d0c73SAureo Serrano de Souza * late-arriving ACK from a timed-out write from erroneously 104*e28d0c73SAureo Serrano de Souza * satisfying a subsequent write's completion wait. 105*e28d0c73SAureo Serrano de Souza */ 106*e28d0c73SAureo Serrano de Souza if (priv->write_pending) { 107*e28d0c73SAureo Serrano de Souza priv->ack_status = data[1] == 0x00 ? 0 : -EIO; 108*e28d0c73SAureo Serrano de Souza complete(&priv->in_report_received); 109*e28d0c73SAureo Serrano de Souza } 110*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 111*e28d0c73SAureo Serrano de Souza return 0; 112*e28d0c73SAureo Serrano de Souza } 113*e28d0c73SAureo Serrano de Souza 114*e28d0c73SAureo Serrano de Souza if (report->id != ARCTIC_OUTPUT_REPORT_ID || size != ARCTIC_REPORT_LEN) { 115*e28d0c73SAureo Serrano de Souza hid_dbg(hdev, "arctic_fan: raw_event id=%u size=%d ignored\n", 116*e28d0c73SAureo Serrano de Souza report->id, size); 117*e28d0c73SAureo Serrano de Souza return 0; 118*e28d0c73SAureo Serrano de Souza } 119*e28d0c73SAureo Serrano de Souza 120*e28d0c73SAureo Serrano de Souza arctic_fan_parse_report(priv, data, size, ARCTIC_RPM_OFFSET); 121*e28d0c73SAureo Serrano de Souza return 0; 122*e28d0c73SAureo Serrano de Souza } 123*e28d0c73SAureo Serrano de Souza 124*e28d0c73SAureo Serrano de Souza static umode_t arctic_fan_is_visible(const void *data, 125*e28d0c73SAureo Serrano de Souza enum hwmon_sensor_types type, 126*e28d0c73SAureo Serrano de Souza u32 attr, int channel) 127*e28d0c73SAureo Serrano de Souza { 128*e28d0c73SAureo Serrano de Souza if (type == hwmon_fan && attr == hwmon_fan_input) 129*e28d0c73SAureo Serrano de Souza return 0444; 130*e28d0c73SAureo Serrano de Souza if (type == hwmon_pwm && attr == hwmon_pwm_input) 131*e28d0c73SAureo Serrano de Souza return 0644; 132*e28d0c73SAureo Serrano de Souza return 0; 133*e28d0c73SAureo Serrano de Souza } 134*e28d0c73SAureo Serrano de Souza 135*e28d0c73SAureo Serrano de Souza static int arctic_fan_read(struct device *dev, enum hwmon_sensor_types type, 136*e28d0c73SAureo Serrano de Souza u32 attr, int channel, long *val) 137*e28d0c73SAureo Serrano de Souza { 138*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv = dev_get_drvdata(dev); 139*e28d0c73SAureo Serrano de Souza unsigned long flags; 140*e28d0c73SAureo Serrano de Souza 141*e28d0c73SAureo Serrano de Souza if (type == hwmon_fan && attr == hwmon_fan_input) { 142*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 143*e28d0c73SAureo Serrano de Souza *val = priv->fan_rpm[channel]; 144*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 145*e28d0c73SAureo Serrano de Souza return 0; 146*e28d0c73SAureo Serrano de Souza } 147*e28d0c73SAureo Serrano de Souza if (type == hwmon_pwm && attr == hwmon_pwm_input) { 148*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 149*e28d0c73SAureo Serrano de Souza *val = priv->pwm_duty[channel]; 150*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 151*e28d0c73SAureo Serrano de Souza return 0; 152*e28d0c73SAureo Serrano de Souza } 153*e28d0c73SAureo Serrano de Souza return -EINVAL; 154*e28d0c73SAureo Serrano de Souza } 155*e28d0c73SAureo Serrano de Souza 156*e28d0c73SAureo Serrano de Souza static int arctic_fan_write(struct device *dev, enum hwmon_sensor_types type, 157*e28d0c73SAureo Serrano de Souza u32 attr, int channel, long val) 158*e28d0c73SAureo Serrano de Souza { 159*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv = dev_get_drvdata(dev); 160*e28d0c73SAureo Serrano de Souza u8 new_duty = (u8)clamp_val(val, 0, 255); 161*e28d0c73SAureo Serrano de Souza unsigned long flags; 162*e28d0c73SAureo Serrano de Souza unsigned long t; 163*e28d0c73SAureo Serrano de Souza int i, ret; 164*e28d0c73SAureo Serrano de Souza 165*e28d0c73SAureo Serrano de Souza /* 166*e28d0c73SAureo Serrano de Souza * Build the buffer and arm write_pending under in_report_lock so that 167*e28d0c73SAureo Serrano de Souza * reset_resume() cannot clear pwm_duty[] between the pwm_duty[] read 168*e28d0c73SAureo Serrano de Souza * and the buffer write, and raw_event() cannot deliver a stale ACK 169*e28d0c73SAureo Serrano de Souza * from a previous write into this write's completion. 170*e28d0c73SAureo Serrano de Souza * 171*e28d0c73SAureo Serrano de Souza * priv->buf is heap-allocated (embedded in the devm_kzalloc'd struct), 172*e28d0c73SAureo Serrano de Souza * satisfying usb_hcd_map_urb_for_dma(). Exclusively accessed by 173*e28d0c73SAureo Serrano de Souza * write() which the hwmon core serializes. 174*e28d0c73SAureo Serrano de Souza * 175*e28d0c73SAureo Serrano de Souza * pwm_duty[channel] is committed only after a positive device ACK so a 176*e28d0c73SAureo Serrano de Souza * failed or timed-out write does not corrupt the cached state. 177*e28d0c73SAureo Serrano de Souza * 178*e28d0c73SAureo Serrano de Souza * Residual theoretical race: if write A times out (write_pending 179*e28d0c73SAureo Serrano de Souza * cleared), write B sets write_pending = true, and a late ACK from 180*e28d0c73SAureo Serrano de Souza * write A—delayed beyond ARCTIC_ACK_TIMEOUT_MS—arrives during write 181*e28d0c73SAureo Serrano de Souza * B's pending window, it would falsely satisfy write B's completion. 182*e28d0c73SAureo Serrano de Souza * This cannot be prevented in driver code without protocol support 183*e28d0c73SAureo Serrano de Souza * (for example, a correlation ID echoed in the device ACK report). 184*e28d0c73SAureo Serrano de Souza * In testing, observed ACK latency stayed below the 1 s timeout 185*e28d0c73SAureo Serrano de Souza * (maximum ~563 ms over 500 iterations). 186*e28d0c73SAureo Serrano de Souza * 187*e28d0c73SAureo Serrano de Souza * The wait is non-interruptible so that a signal cannot cause write() 188*e28d0c73SAureo Serrano de Souza * to return early while the OUT report is already in flight; an 189*e28d0c73SAureo Serrano de Souza * interruptible early return would create the same late-ACK window 190*e28d0c73SAureo Serrano de Souza * without even the timeout guard. 191*e28d0c73SAureo Serrano de Souza * Serialized by the hwmon core: only one arctic_fan_write() at a time. 192*e28d0c73SAureo Serrano de Souza * Use irqsave to match the IRQ context in which raw_event may run. 193*e28d0c73SAureo Serrano de Souza */ 194*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 195*e28d0c73SAureo Serrano de Souza priv->buf[0] = ARCTIC_OUTPUT_REPORT_ID; 196*e28d0c73SAureo Serrano de Souza for (i = 0; i < ARCTIC_NUM_FANS; i++) { 197*e28d0c73SAureo Serrano de Souza u8 d = i == channel ? new_duty : priv->pwm_duty[i]; 198*e28d0c73SAureo Serrano de Souza 199*e28d0c73SAureo Serrano de Souza priv->buf[1 + i] = DIV_ROUND_CLOSEST((unsigned int)d * 100, 255); 200*e28d0c73SAureo Serrano de Souza } 201*e28d0c73SAureo Serrano de Souza priv->ack_status = -ETIMEDOUT; 202*e28d0c73SAureo Serrano de Souza priv->write_pending = true; 203*e28d0c73SAureo Serrano de Souza reinit_completion(&priv->in_report_received); 204*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 205*e28d0c73SAureo Serrano de Souza 206*e28d0c73SAureo Serrano de Souza ret = hid_hw_output_report(priv->hdev, priv->buf, ARCTIC_REPORT_LEN); 207*e28d0c73SAureo Serrano de Souza if (ret < 0) { 208*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 209*e28d0c73SAureo Serrano de Souza priv->write_pending = false; 210*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 211*e28d0c73SAureo Serrano de Souza return ret; 212*e28d0c73SAureo Serrano de Souza } 213*e28d0c73SAureo Serrano de Souza 214*e28d0c73SAureo Serrano de Souza t = wait_for_completion_timeout(&priv->in_report_received, 215*e28d0c73SAureo Serrano de Souza msecs_to_jiffies(ARCTIC_ACK_TIMEOUT_MS)); 216*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 217*e28d0c73SAureo Serrano de Souza priv->write_pending = false; 218*e28d0c73SAureo Serrano de Souza /* Commit inside the lock so reset_resume() cannot race with this write */ 219*e28d0c73SAureo Serrano de Souza if (t && priv->ack_status == 0) 220*e28d0c73SAureo Serrano de Souza priv->pwm_duty[channel] = new_duty; 221*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 222*e28d0c73SAureo Serrano de Souza 223*e28d0c73SAureo Serrano de Souza if (!t) 224*e28d0c73SAureo Serrano de Souza return -ETIMEDOUT; 225*e28d0c73SAureo Serrano de Souza return priv->ack_status; /* 0=OK, -EIO=device error */ 226*e28d0c73SAureo Serrano de Souza } 227*e28d0c73SAureo Serrano de Souza 228*e28d0c73SAureo Serrano de Souza static const struct hwmon_ops arctic_fan_ops = { 229*e28d0c73SAureo Serrano de Souza .is_visible = arctic_fan_is_visible, 230*e28d0c73SAureo Serrano de Souza .read = arctic_fan_read, 231*e28d0c73SAureo Serrano de Souza .write = arctic_fan_write, 232*e28d0c73SAureo Serrano de Souza }; 233*e28d0c73SAureo Serrano de Souza 234*e28d0c73SAureo Serrano de Souza static const struct hwmon_channel_info *arctic_fan_info[] = { 235*e28d0c73SAureo Serrano de Souza HWMON_CHANNEL_INFO(fan, 236*e28d0c73SAureo Serrano de Souza HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT, 237*e28d0c73SAureo Serrano de Souza HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT, 238*e28d0c73SAureo Serrano de Souza HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT, 239*e28d0c73SAureo Serrano de Souza HWMON_F_INPUT), 240*e28d0c73SAureo Serrano de Souza HWMON_CHANNEL_INFO(pwm, 241*e28d0c73SAureo Serrano de Souza HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT, 242*e28d0c73SAureo Serrano de Souza HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT, 243*e28d0c73SAureo Serrano de Souza HWMON_PWM_INPUT, HWMON_PWM_INPUT, HWMON_PWM_INPUT, 244*e28d0c73SAureo Serrano de Souza HWMON_PWM_INPUT), 245*e28d0c73SAureo Serrano de Souza NULL 246*e28d0c73SAureo Serrano de Souza }; 247*e28d0c73SAureo Serrano de Souza 248*e28d0c73SAureo Serrano de Souza static const struct hwmon_chip_info arctic_fan_chip_info = { 249*e28d0c73SAureo Serrano de Souza .ops = &arctic_fan_ops, 250*e28d0c73SAureo Serrano de Souza .info = arctic_fan_info, 251*e28d0c73SAureo Serrano de Souza }; 252*e28d0c73SAureo Serrano de Souza 253*e28d0c73SAureo Serrano de Souza static int arctic_fan_reset_resume(struct hid_device *hdev) 254*e28d0c73SAureo Serrano de Souza { 255*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv = hid_get_drvdata(hdev); 256*e28d0c73SAureo Serrano de Souza unsigned long flags; 257*e28d0c73SAureo Serrano de Souza 258*e28d0c73SAureo Serrano de Souza /* 259*e28d0c73SAureo Serrano de Souza * The device resets its PWM channels to hardware defaults on power 260*e28d0c73SAureo Serrano de Souza * loss during suspend. Clear the cached duty values so they reflect 261*e28d0c73SAureo Serrano de Souza * the unknown hardware state, consistent with probe-time behaviour 262*e28d0c73SAureo Serrano de Souza * (the device has no GET_REPORT support). Hold in_report_lock so 263*e28d0c73SAureo Serrano de Souza * this does not race with a concurrent pwm read or write callback. 264*e28d0c73SAureo Serrano de Souza */ 265*e28d0c73SAureo Serrano de Souza spin_lock_irqsave(&priv->in_report_lock, flags); 266*e28d0c73SAureo Serrano de Souza memset(priv->pwm_duty, 0, sizeof(priv->pwm_duty)); 267*e28d0c73SAureo Serrano de Souza spin_unlock_irqrestore(&priv->in_report_lock, flags); 268*e28d0c73SAureo Serrano de Souza return 0; 269*e28d0c73SAureo Serrano de Souza } 270*e28d0c73SAureo Serrano de Souza 271*e28d0c73SAureo Serrano de Souza static int arctic_fan_probe(struct hid_device *hdev, 272*e28d0c73SAureo Serrano de Souza const struct hid_device_id *id) 273*e28d0c73SAureo Serrano de Souza { 274*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv; 275*e28d0c73SAureo Serrano de Souza int ret; 276*e28d0c73SAureo Serrano de Souza 277*e28d0c73SAureo Serrano de Souza if (!hid_is_usb(hdev)) 278*e28d0c73SAureo Serrano de Souza return -ENODEV; 279*e28d0c73SAureo Serrano de Souza 280*e28d0c73SAureo Serrano de Souza ret = hid_parse(hdev); 281*e28d0c73SAureo Serrano de Souza if (ret) 282*e28d0c73SAureo Serrano de Souza return ret; 283*e28d0c73SAureo Serrano de Souza 284*e28d0c73SAureo Serrano de Souza priv = devm_kzalloc(&hdev->dev, sizeof(*priv), GFP_KERNEL); 285*e28d0c73SAureo Serrano de Souza if (!priv) 286*e28d0c73SAureo Serrano de Souza return -ENOMEM; 287*e28d0c73SAureo Serrano de Souza 288*e28d0c73SAureo Serrano de Souza priv->hdev = hdev; 289*e28d0c73SAureo Serrano de Souza spin_lock_init(&priv->in_report_lock); 290*e28d0c73SAureo Serrano de Souza init_completion(&priv->in_report_received); 291*e28d0c73SAureo Serrano de Souza hid_set_drvdata(hdev, priv); 292*e28d0c73SAureo Serrano de Souza 293*e28d0c73SAureo Serrano de Souza ret = hid_hw_start(hdev, HID_CONNECT_DRIVER); 294*e28d0c73SAureo Serrano de Souza if (ret) 295*e28d0c73SAureo Serrano de Souza return ret; 296*e28d0c73SAureo Serrano de Souza 297*e28d0c73SAureo Serrano de Souza ret = hid_hw_open(hdev); 298*e28d0c73SAureo Serrano de Souza if (ret) 299*e28d0c73SAureo Serrano de Souza goto out_stop; 300*e28d0c73SAureo Serrano de Souza 301*e28d0c73SAureo Serrano de Souza /* 302*e28d0c73SAureo Serrano de Souza * Start IO before registering with hwmon. If IO were started after 303*e28d0c73SAureo Serrano de Souza * hwmon registration, a sysfs write arriving in that narrow window 304*e28d0c73SAureo Serrano de Souza * would send an OUT report but the ACK could not be delivered (the HID 305*e28d0c73SAureo Serrano de Souza * core discards events until io_started), causing a spurious timeout. 306*e28d0c73SAureo Serrano de Souza */ 307*e28d0c73SAureo Serrano de Souza hid_device_io_start(hdev); 308*e28d0c73SAureo Serrano de Souza 309*e28d0c73SAureo Serrano de Souza /* 310*e28d0c73SAureo Serrano de Souza * Use the non-devm variant and store the pointer so remove() can 311*e28d0c73SAureo Serrano de Souza * call hwmon_device_unregister() before tearing down the HID 312*e28d0c73SAureo Serrano de Souza * transport. devm_hwmon_device_register_with_info() would defer 313*e28d0c73SAureo Serrano de Souza * unregistration until after remove() returns, leaving a window 314*e28d0c73SAureo Serrano de Souza * where a concurrent sysfs write could call hid_hw_output_report() 315*e28d0c73SAureo Serrano de Souza * on an already-stopped device (use-after-free). 316*e28d0c73SAureo Serrano de Souza */ 317*e28d0c73SAureo Serrano de Souza priv->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "arctic_fan", 318*e28d0c73SAureo Serrano de Souza priv, &arctic_fan_chip_info, 319*e28d0c73SAureo Serrano de Souza NULL); 320*e28d0c73SAureo Serrano de Souza if (IS_ERR(priv->hwmon_dev)) { 321*e28d0c73SAureo Serrano de Souza ret = PTR_ERR(priv->hwmon_dev); 322*e28d0c73SAureo Serrano de Souza goto out_close; 323*e28d0c73SAureo Serrano de Souza } 324*e28d0c73SAureo Serrano de Souza 325*e28d0c73SAureo Serrano de Souza return 0; 326*e28d0c73SAureo Serrano de Souza 327*e28d0c73SAureo Serrano de Souza out_close: 328*e28d0c73SAureo Serrano de Souza hid_device_io_stop(hdev); 329*e28d0c73SAureo Serrano de Souza hid_hw_close(hdev); 330*e28d0c73SAureo Serrano de Souza out_stop: 331*e28d0c73SAureo Serrano de Souza hid_hw_stop(hdev); 332*e28d0c73SAureo Serrano de Souza return ret; 333*e28d0c73SAureo Serrano de Souza } 334*e28d0c73SAureo Serrano de Souza 335*e28d0c73SAureo Serrano de Souza static void arctic_fan_remove(struct hid_device *hdev) 336*e28d0c73SAureo Serrano de Souza { 337*e28d0c73SAureo Serrano de Souza struct arctic_fan_data *priv = hid_get_drvdata(hdev); 338*e28d0c73SAureo Serrano de Souza 339*e28d0c73SAureo Serrano de Souza /* 340*e28d0c73SAureo Serrano de Souza * Unregister hwmon before stopping the HID transport. This removes 341*e28d0c73SAureo Serrano de Souza * the sysfs files and waits for any in-progress write() callback to 342*e28d0c73SAureo Serrano de Souza * return, so no hwmon op can call hid_hw_output_report() after 343*e28d0c73SAureo Serrano de Souza * hid_hw_stop() frees the underlying USB resources. 344*e28d0c73SAureo Serrano de Souza * Matches the pattern used by nzxt-smart2 and aquacomputer_d5next. 345*e28d0c73SAureo Serrano de Souza * 346*e28d0c73SAureo Serrano de Souza * The HID core clears hdev->io_started before invoking ->remove(), 347*e28d0c73SAureo Serrano de Souza * so hid_device_io_stop() is not called here; doing so would emit 348*e28d0c73SAureo Serrano de Souza * a spurious "io already stopped" warning. 349*e28d0c73SAureo Serrano de Souza */ 350*e28d0c73SAureo Serrano de Souza hwmon_device_unregister(priv->hwmon_dev); 351*e28d0c73SAureo Serrano de Souza hid_hw_close(hdev); 352*e28d0c73SAureo Serrano de Souza hid_hw_stop(hdev); 353*e28d0c73SAureo Serrano de Souza } 354*e28d0c73SAureo Serrano de Souza 355*e28d0c73SAureo Serrano de Souza static const struct hid_device_id arctic_fan_id_table[] = { 356*e28d0c73SAureo Serrano de Souza { HID_USB_DEVICE(ARCTIC_VID, ARCTIC_PID) }, 357*e28d0c73SAureo Serrano de Souza { } 358*e28d0c73SAureo Serrano de Souza }; 359*e28d0c73SAureo Serrano de Souza MODULE_DEVICE_TABLE(hid, arctic_fan_id_table); 360*e28d0c73SAureo Serrano de Souza 361*e28d0c73SAureo Serrano de Souza static struct hid_driver arctic_fan_driver = { 362*e28d0c73SAureo Serrano de Souza .name = "arctic_fan", 363*e28d0c73SAureo Serrano de Souza .id_table = arctic_fan_id_table, 364*e28d0c73SAureo Serrano de Souza .probe = arctic_fan_probe, 365*e28d0c73SAureo Serrano de Souza .remove = arctic_fan_remove, 366*e28d0c73SAureo Serrano de Souza .raw_event = arctic_fan_raw_event, 367*e28d0c73SAureo Serrano de Souza .reset_resume = arctic_fan_reset_resume, 368*e28d0c73SAureo Serrano de Souza }; 369*e28d0c73SAureo Serrano de Souza 370*e28d0c73SAureo Serrano de Souza module_hid_driver(arctic_fan_driver); 371*e28d0c73SAureo Serrano de Souza 372*e28d0c73SAureo Serrano de Souza MODULE_AUTHOR("Aureo Serrano de Souza <aureo.serrano@arctic.de>"); 373*e28d0c73SAureo Serrano de Souza MODULE_DESCRIPTION("HID hwmon driver for ARCTIC Fan Controller"); 374*e28d0c73SAureo Serrano de Souza MODULE_LICENSE("GPL"); 375