| From 7c49e87acd0412ff1fb2490c4ac6fcb5471afd9b Mon Sep 17 00:00:00 2001 |
| From: Akira Shimahara <akira215corp@gmail.com> |
| Date: Mon, 11 May 2020 22:35:35 +0200 |
| Subject: [PATCH] w1_therm: adding code comments and code reordering |
| |
| commit 92b8d2724464bc1d2e735a84c0da5741dce33485 upstream. |
| |
| Adding code comments to split code in dedicated parts. After the global |
| declarations (defines, macros and function declarations), code is organized |
| as follow : |
| - Device and family dependent structures and functions |
| - Interfaces functions |
| - Helpers functions |
| - Hardware functions |
| - Sysfs interface functions |
| |
| Signed-off-by: Akira Shimahara <akira215corp@gmail.com> |
| Link: https://lore.kernel.org/r/20200511203535.409599-1-akira215corp@gmail.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/w1/slaves/w1_therm.c | 427 +++++++++++++++++++++-------------- |
| 1 file changed, 259 insertions(+), 168 deletions(-) |
| |
| --- a/drivers/w1/slaves/w1_therm.c |
| +++ b/drivers/w1/slaves/w1_therm.c |
| @@ -25,7 +25,8 @@ |
| #define W1_THERM_DS1825 0x3B |
| #define W1_THERM_DS28EA00 0x42 |
| |
| -/* Allow the strong pullup to be disabled, but default to enabled. |
| +/* |
| + * Allow the strong pullup to be disabled, but default to enabled. |
| * If it was disabled a parasite powered device might not get the require |
| * current to do a temperature conversion. If it is enabled parasite powered |
| * devices have a better chance of getting the current required. |
| @@ -41,42 +42,55 @@ |
| static int w1_strong_pullup = 1; |
| module_param_named(strong_pullup, w1_strong_pullup, int, 0); |
| |
| +/* Helpers Macros */ |
| + |
| +/* return the address of the refcnt in the family data */ |
| +#define THERM_REFCNT(family_data) \ |
| + (&((struct w1_therm_family_data *)family_data)->refcnt) |
| + |
| +/* Structs definition */ |
| + |
| +/** |
| + * struct w1_therm_family_converter - bind device specific functions |
| + * @broken: flag for non-registred families |
| + * @reserved: not used here |
| + * @f: pointer to the device binding structure |
| + * @convert: pointer to the device conversion function |
| + * @precision: pointer to the device precision function |
| + * @eeprom: pointer to eeprom function |
| + */ |
| +struct w1_therm_family_converter { |
| + u8 broken; |
| + u16 reserved; |
| + struct w1_family *f; |
| + int (*convert)(u8 rom[9]); |
| + int (*precision)(struct device *device, int val); |
| + int (*eeprom)(struct device *device); |
| +}; |
| + |
| +/** |
| + * struct w1_therm_family_data - device data |
| + * @rom: ROM device id (64bit Lasered ROM code + 1 CRC byte) |
| + * @refcnt: ref count |
| + */ |
| struct w1_therm_family_data { |
| uint8_t rom[9]; |
| atomic_t refcnt; |
| }; |
| |
| +/** |
| + * struct therm_info - store temperature reading |
| + * @rom: read device data (8 data bytes + 1 CRC byte) |
| + * @crc: computed crc from rom |
| + * @verdict: 1 crc checked, 0 crc not matching |
| + */ |
| struct therm_info { |
| u8 rom[9]; |
| u8 crc; |
| u8 verdict; |
| }; |
| |
| -/* return the address of the refcnt in the family data */ |
| -#define THERM_REFCNT(family_data) \ |
| - (&((struct w1_therm_family_data *)family_data)->refcnt) |
| - |
| -static int w1_therm_add_slave(struct w1_slave *sl) |
| -{ |
| - sl->family_data = kzalloc(sizeof(struct w1_therm_family_data), |
| - GFP_KERNEL); |
| - if (!sl->family_data) |
| - return -ENOMEM; |
| - atomic_set(THERM_REFCNT(sl->family_data), 1); |
| - return 0; |
| -} |
| - |
| -static void w1_therm_remove_slave(struct w1_slave *sl) |
| -{ |
| - int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data)); |
| - |
| - while (refcnt) { |
| - msleep(1000); |
| - refcnt = atomic_read(THERM_REFCNT(sl->family_data)); |
| - } |
| - kfree(sl->family_data); |
| - sl->family_data = NULL; |
| -} |
| +/* Sysfs interface declaration */ |
| |
| static ssize_t w1_slave_show(struct device *device, |
| struct device_attribute *attr, char *buf); |
| @@ -87,9 +101,35 @@ static ssize_t w1_slave_store(struct dev |
| static ssize_t w1_seq_show(struct device *device, |
| struct device_attribute *attr, char *buf); |
| |
| +/* Attributes declarations */ |
| + |
| static DEVICE_ATTR_RW(w1_slave); |
| static DEVICE_ATTR_RO(w1_seq); |
| |
| +/* Interface Functions declaration */ |
| + |
| +/** |
| + * w1_therm_add_slave() - Called when a new slave is discovered |
| + * @sl: slave just discovered by the master. |
| + * |
| + * Called by the master when the slave is discovered on the bus. Used to |
| + * initialize slave state before the beginning of any communication. |
| + * |
| + * Return: 0 - If success, negative kernel code otherwise |
| + */ |
| +static int w1_therm_add_slave(struct w1_slave *sl); |
| + |
| +/** |
| + * w1_therm_remove_slave() - Called when a slave is removed |
| + * @sl: slave to be removed. |
| + * |
| + * Called by the master when the slave is considered not to be on the bus |
| + * anymore. Used to free memory. |
| + */ |
| +static void w1_therm_remove_slave(struct w1_slave *sl); |
| + |
| +/* Family attributes */ |
| + |
| static struct attribute *w1_therm_attrs[] = { |
| &dev_attr_w1_slave.attr, |
| NULL, |
| @@ -101,6 +141,8 @@ static struct attribute *w1_ds28ea00_att |
| NULL, |
| }; |
| |
| +/* Attribute groups */ |
| + |
| ATTRIBUTE_GROUPS(w1_therm); |
| ATTRIBUTE_GROUPS(w1_ds28ea00); |
| |
| @@ -154,6 +196,8 @@ static const struct hwmon_chip_info w1_c |
| #define W1_CHIPINFO NULL |
| #endif |
| |
| +/* Family operations */ |
| + |
| static struct w1_family_ops w1_therm_fops = { |
| .add_slave = w1_therm_add_slave, |
| .remove_slave = w1_therm_remove_slave, |
| @@ -168,6 +212,8 @@ static struct w1_family_ops w1_ds28ea00_ |
| .chip_info = W1_CHIPINFO, |
| }; |
| |
| +/* Family binding operations struct */ |
| + |
| static struct w1_family w1_therm_family_DS18S20 = { |
| .fid = W1_THERM_DS18S20, |
| .fops = &w1_therm_fops, |
| @@ -193,138 +239,18 @@ static struct w1_family w1_therm_family_ |
| .fops = &w1_therm_fops, |
| }; |
| |
| -struct w1_therm_family_converter { |
| - u8 broken; |
| - u16 reserved; |
| - struct w1_family *f; |
| - int (*convert)(u8 rom[9]); |
| - int (*precision)(struct device *device, int val); |
| - int (*eeprom)(struct device *device); |
| -}; |
| +/* Device dependent func */ |
| |
| /* write configuration to eeprom */ |
| static inline int w1_therm_eeprom(struct device *device); |
| |
| -/* Set precision for conversion */ |
| -static inline int w1_DS18B20_precision(struct device *device, int val); |
| -static inline int w1_DS18S20_precision(struct device *device, int val); |
| - |
| -/* The return value is millidegrees Centigrade. */ |
| -static inline int w1_DS18B20_convert_temp(u8 rom[9]); |
| -static inline int w1_DS18S20_convert_temp(u8 rom[9]); |
| - |
| -static struct w1_therm_family_converter w1_therm_families[] = { |
| - { |
| - .f = &w1_therm_family_DS18S20, |
| - .convert = w1_DS18S20_convert_temp, |
| - .precision = w1_DS18S20_precision, |
| - .eeprom = w1_therm_eeprom |
| - }, |
| - { |
| - .f = &w1_therm_family_DS1822, |
| - .convert = w1_DS18B20_convert_temp, |
| - .precision = w1_DS18S20_precision, |
| - .eeprom = w1_therm_eeprom |
| - }, |
| - { |
| - .f = &w1_therm_family_DS18B20, |
| - .convert = w1_DS18B20_convert_temp, |
| - .precision = w1_DS18B20_precision, |
| - .eeprom = w1_therm_eeprom |
| - }, |
| - { |
| - .f = &w1_therm_family_DS28EA00, |
| - .convert = w1_DS18B20_convert_temp, |
| - .precision = w1_DS18S20_precision, |
| - .eeprom = w1_therm_eeprom |
| - }, |
| - { |
| - .f = &w1_therm_family_DS1825, |
| - .convert = w1_DS18B20_convert_temp, |
| - .precision = w1_DS18S20_precision, |
| - .eeprom = w1_therm_eeprom |
| - } |
| -}; |
| - |
| -static inline int w1_therm_eeprom(struct device *device) |
| -{ |
| - struct w1_slave *sl = dev_to_w1_slave(device); |
| - struct w1_master *dev = sl->master; |
| - u8 rom[9], external_power; |
| - int ret, max_trying = 10; |
| - u8 *family_data = sl->family_data; |
| - |
| - if (!sl->family_data) { |
| - ret = -ENODEV; |
| - goto error; |
| - } |
| - |
| - /* prevent the slave from going away in sleep */ |
| - atomic_inc(THERM_REFCNT(family_data)); |
| - |
| - ret = mutex_lock_interruptible(&dev->bus_mutex); |
| - if (ret != 0) |
| - goto dec_refcnt; |
| - |
| - memset(rom, 0, sizeof(rom)); |
| - |
| - while (max_trying--) { |
| - if (!w1_reset_select_slave(sl)) { |
| - unsigned int tm = 10; |
| - unsigned long sleep_rem; |
| - |
| - /* check if in parasite mode */ |
| - w1_write_8(dev, W1_READ_PSUPPLY); |
| - external_power = w1_read_8(dev); |
| - |
| - if (w1_reset_select_slave(sl)) |
| - continue; |
| - |
| - /* 10ms strong pullup/delay after the copy command */ |
| - if (w1_strong_pullup == 2 || |
| - (!external_power && w1_strong_pullup)) |
| - w1_next_pullup(dev, tm); |
| - |
| - w1_write_8(dev, W1_COPY_SCRATCHPAD); |
| - |
| - if (external_power) { |
| - mutex_unlock(&dev->bus_mutex); |
| - |
| - sleep_rem = msleep_interruptible(tm); |
| - if (sleep_rem != 0) { |
| - ret = -EINTR; |
| - goto dec_refcnt; |
| - } |
| - |
| - ret = mutex_lock_interruptible(&dev->bus_mutex); |
| - if (ret != 0) |
| - goto dec_refcnt; |
| - } else if (!w1_strong_pullup) { |
| - sleep_rem = msleep_interruptible(tm); |
| - if (sleep_rem != 0) { |
| - ret = -EINTR; |
| - goto mt_unlock; |
| - } |
| - } |
| - |
| - break; |
| - } |
| - } |
| - |
| -mt_unlock: |
| - mutex_unlock(&dev->bus_mutex); |
| -dec_refcnt: |
| - atomic_dec(THERM_REFCNT(family_data)); |
| -error: |
| - return ret; |
| -} |
| - |
| /* DS18S20 does not feature configuration register */ |
| static inline int w1_DS18S20_precision(struct device *device, int val) |
| { |
| return 0; |
| } |
| |
| +/* Set precision for conversion */ |
| static inline int w1_DS18B20_precision(struct device *device, int val) |
| { |
| struct w1_slave *sl = dev_to_w1_slave(device); |
| @@ -407,6 +333,14 @@ error: |
| return ret; |
| } |
| |
| +/** |
| + * w1_DS18B20_convert_temp() - temperature computation for DS18B20 |
| + * @rom: data read from device RAM (8 data bytes + 1 CRC byte) |
| + * |
| + * Can be called for any DS18B20 compliant device. |
| + * |
| + * Return: value in millidegrees Celsius. |
| + */ |
| static inline int w1_DS18B20_convert_temp(u8 rom[9]) |
| { |
| s16 t = le16_to_cpup((__le16 *)rom); |
| @@ -414,6 +348,14 @@ static inline int w1_DS18B20_convert_tem |
| return t*1000/16; |
| } |
| |
| +/** |
| + * w1_DS18S20_convert_temp() - temperature computation for DS18S20 |
| + * @rom: data read from device RAM (8 data bytes + 1 CRC byte) |
| + * |
| + * Can be called for any DS18S20 compliant device. |
| + * |
| + * Return: value in millidegrees Celsius. |
| + */ |
| static inline int w1_DS18S20_convert_temp(u8 rom[9]) |
| { |
| int t, h; |
| @@ -434,6 +376,53 @@ static inline int w1_DS18S20_convert_tem |
| return t; |
| } |
| |
| +/* Device capability description */ |
| + |
| +static struct w1_therm_family_converter w1_therm_families[] = { |
| + { |
| + .f = &w1_therm_family_DS18S20, |
| + .convert = w1_DS18S20_convert_temp, |
| + .precision = w1_DS18S20_precision, |
| + .eeprom = w1_therm_eeprom |
| + }, |
| + { |
| + .f = &w1_therm_family_DS1822, |
| + .convert = w1_DS18B20_convert_temp, |
| + .precision = w1_DS18S20_precision, |
| + .eeprom = w1_therm_eeprom |
| + }, |
| + { |
| + .f = &w1_therm_family_DS18B20, |
| + .convert = w1_DS18B20_convert_temp, |
| + .precision = w1_DS18B20_precision, |
| + .eeprom = w1_therm_eeprom |
| + }, |
| + { |
| + .f = &w1_therm_family_DS28EA00, |
| + .convert = w1_DS18B20_convert_temp, |
| + .precision = w1_DS18S20_precision, |
| + .eeprom = w1_therm_eeprom |
| + }, |
| + { |
| + .f = &w1_therm_family_DS1825, |
| + .convert = w1_DS18B20_convert_temp, |
| + .precision = w1_DS18S20_precision, |
| + .eeprom = w1_therm_eeprom |
| + } |
| +}; |
| + |
| +/* Helpers Functions */ |
| + |
| +/** |
| + * w1_convert_temp() - temperature conversion binding function |
| + * @rom: data read from device RAM (8 data bytes + 1 CRC byte) |
| + * @fid: device family id |
| + * |
| + * The function call the temperature computation function according to |
| + * device family. |
| + * |
| + * Return: value in millidegrees Celsius. |
| + */ |
| static inline int w1_convert_temp(u8 rom[9], u8 fid) |
| { |
| int i; |
| @@ -445,31 +434,32 @@ static inline int w1_convert_temp(u8 rom |
| return 0; |
| } |
| |
| -static ssize_t w1_slave_store(struct device *device, |
| - struct device_attribute *attr, const char *buf, |
| - size_t size) |
| +/* Interface Functions */ |
| + |
| +static int w1_therm_add_slave(struct w1_slave *sl) |
| { |
| - int val, ret; |
| - struct w1_slave *sl = dev_to_w1_slave(device); |
| - int i; |
| + sl->family_data = kzalloc(sizeof(struct w1_therm_family_data), |
| + GFP_KERNEL); |
| + if (!sl->family_data) |
| + return -ENOMEM; |
| + atomic_set(THERM_REFCNT(sl->family_data), 1); |
| + return 0; |
| +} |
| |
| - ret = kstrtoint(buf, 0, &val); |
| - if (ret) |
| - return ret; |
| +static void w1_therm_remove_slave(struct w1_slave *sl) |
| +{ |
| + int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data)); |
| |
| - for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { |
| - if (w1_therm_families[i].f->fid == sl->family->fid) { |
| - /* zero value indicates to write current configuration to eeprom */ |
| - if (val == 0) |
| - ret = w1_therm_families[i].eeprom(device); |
| - else |
| - ret = w1_therm_families[i].precision(device, val); |
| - break; |
| - } |
| + while (refcnt) { |
| + msleep(1000); |
| + refcnt = atomic_read(THERM_REFCNT(sl->family_data)); |
| } |
| - return ret ? : size; |
| + kfree(sl->family_data); |
| + sl->family_data = NULL; |
| } |
| |
| +/* Hardware Functions */ |
| + |
| static ssize_t read_therm(struct device *device, |
| struct w1_slave *sl, struct therm_info *info) |
| { |
| @@ -564,6 +554,81 @@ error: |
| return ret; |
| } |
| |
| +static inline int w1_therm_eeprom(struct device *device) |
| +{ |
| + struct w1_slave *sl = dev_to_w1_slave(device); |
| + struct w1_master *dev = sl->master; |
| + u8 rom[9], external_power; |
| + int ret, max_trying = 10; |
| + u8 *family_data = sl->family_data; |
| + |
| + if (!sl->family_data) { |
| + ret = -ENODEV; |
| + goto error; |
| + } |
| + |
| + /* prevent the slave from going away in sleep */ |
| + atomic_inc(THERM_REFCNT(family_data)); |
| + |
| + ret = mutex_lock_interruptible(&dev->bus_mutex); |
| + if (ret != 0) |
| + goto dec_refcnt; |
| + |
| + memset(rom, 0, sizeof(rom)); |
| + |
| + while (max_trying--) { |
| + if (!w1_reset_select_slave(sl)) { |
| + unsigned int tm = 10; |
| + unsigned long sleep_rem; |
| + |
| + /* check if in parasite mode */ |
| + w1_write_8(dev, W1_READ_PSUPPLY); |
| + external_power = w1_read_8(dev); |
| + |
| + if (w1_reset_select_slave(sl)) |
| + continue; |
| + |
| + /* 10ms strong pullup/delay after the copy command */ |
| + if (w1_strong_pullup == 2 || |
| + (!external_power && w1_strong_pullup)) |
| + w1_next_pullup(dev, tm); |
| + |
| + w1_write_8(dev, W1_COPY_SCRATCHPAD); |
| + |
| + if (external_power) { |
| + mutex_unlock(&dev->bus_mutex); |
| + |
| + sleep_rem = msleep_interruptible(tm); |
| + if (sleep_rem != 0) { |
| + ret = -EINTR; |
| + goto dec_refcnt; |
| + } |
| + |
| + ret = mutex_lock_interruptible(&dev->bus_mutex); |
| + if (ret != 0) |
| + goto dec_refcnt; |
| + } else if (!w1_strong_pullup) { |
| + sleep_rem = msleep_interruptible(tm); |
| + if (sleep_rem != 0) { |
| + ret = -EINTR; |
| + goto mt_unlock; |
| + } |
| + } |
| + |
| + break; |
| + } |
| + } |
| + |
| +mt_unlock: |
| + mutex_unlock(&dev->bus_mutex); |
| +dec_refcnt: |
| + atomic_dec(THERM_REFCNT(family_data)); |
| +error: |
| + return ret; |
| +} |
| + |
| +/* Sysfs Interface definition */ |
| + |
| static ssize_t w1_slave_show(struct device *device, |
| struct device_attribute *attr, char *buf) |
| { |
| @@ -597,6 +662,32 @@ static ssize_t w1_slave_show(struct devi |
| return ret; |
| } |
| |
| +static ssize_t w1_slave_store(struct device *device, |
| + struct device_attribute *attr, const char *buf, |
| + size_t size) |
| +{ |
| + int val, ret; |
| + struct w1_slave *sl = dev_to_w1_slave(device); |
| + int i; |
| + |
| + ret = kstrtoint(buf, 0, &val); |
| + if (ret) |
| + return ret; |
| + |
| + for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) { |
| + if (w1_therm_families[i].f->fid == sl->family->fid) { |
| + /* zero value indicates to write current configuration to eeprom */ |
| + if (val == 0) |
| + ret = w1_therm_families[i].eeprom(device); |
| + else |
| + ret = w1_therm_families[i].precision(device, |
| + val); |
| + break; |
| + } |
| + } |
| + return ret ? : size; |
| +} |
| + |
| #if IS_REACHABLE(CONFIG_HWMON) |
| static int w1_read_temp(struct device *device, u32 attr, int channel, |
| long *val) |
| @@ -666,7 +757,7 @@ static ssize_t w1_seq_show(struct device |
| if (ack != W1_42_SUCCESS_CONFIRM_BYTE) |
| goto error; |
| |
| - /* In case the bus fails to send 0xFF, limit*/ |
| + /* In case the bus fails to send 0xFF, limit */ |
| for (i = 0; i <= 64; i++) { |
| if (w1_reset_bus(sl->master)) |
| goto error; |