18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/delay.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
108c2ecf20Sopenharmony_ci#include <linux/list.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
138c2ecf20Sopenharmony_ci#include <linux/timer.h>
148c2ecf20Sopenharmony_ci#include <linux/device.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/sched.h>
178c2ecf20Sopenharmony_ci#include <linux/kthread.h>
188c2ecf20Sopenharmony_ci#include <linux/freezer.h>
198c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
208c2ecf20Sopenharmony_ci#include <linux/of.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <linux/atomic.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "w1_internal.h"
258c2ecf20Sopenharmony_ci#include "w1_netlink.h"
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define W1_FAMILY_DEFAULT	0
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic int w1_timeout = 10;
308c2ecf20Sopenharmony_cimodule_param_named(timeout, w1_timeout, int, 0);
318c2ecf20Sopenharmony_ciMODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int w1_timeout_us = 0;
348c2ecf20Sopenharmony_cimodule_param_named(timeout_us, w1_timeout_us, int, 0);
358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(timeout_us,
368c2ecf20Sopenharmony_ci		 "time in microseconds between automatic slave searches");
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/* A search stops when w1_max_slave_count devices have been found in that
398c2ecf20Sopenharmony_ci * search.  The next search will start over and detect the same set of devices
408c2ecf20Sopenharmony_ci * on a static 1-wire bus.  Memory is not allocated based on this number, just
418c2ecf20Sopenharmony_ci * on the number of devices known to the kernel.  Having a high number does not
428c2ecf20Sopenharmony_ci * consume additional resources.  As a special case, if there is only one
438c2ecf20Sopenharmony_ci * device on the network and w1_max_slave_count is set to 1, the device id can
448c2ecf20Sopenharmony_ci * be read directly skipping the normal slower search process.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_ciint w1_max_slave_count = 64;
478c2ecf20Sopenharmony_cimodule_param_named(max_slave_count, w1_max_slave_count, int, 0);
488c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_slave_count,
498c2ecf20Sopenharmony_ci	"maximum number of slaves detected in a search");
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint w1_max_slave_ttl = 10;
528c2ecf20Sopenharmony_cimodule_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(slave_ttl,
548c2ecf20Sopenharmony_ci	"Number of searches not seeing a slave before it will be removed");
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciDEFINE_MUTEX(w1_mlock);
578c2ecf20Sopenharmony_ciLIST_HEAD(w1_masters);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int w1_master_match(struct device *dev, struct device_driver *drv)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	return 1;
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic int w1_master_probe(struct device *dev)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	return -ENODEV;
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic void w1_master_release(struct device *dev)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
748c2ecf20Sopenharmony_ci	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
758c2ecf20Sopenharmony_ci	kfree(md);
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic void w1_slave_release(struct device *dev)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	w1_family_put(sl->family);
858c2ecf20Sopenharmony_ci	sl->master->slave_count--;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", sl->name);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(name);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic ssize_t id_show(struct device *dev,
978c2ecf20Sopenharmony_ci	struct device_attribute *attr, char *buf)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct w1_slave *sl = dev_to_w1_slave(dev);
1008c2ecf20Sopenharmony_ci	ssize_t count = sizeof(sl->reg_num);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	memcpy(buf, (u8 *)&sl->reg_num, count);
1038c2ecf20Sopenharmony_ci	return count;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(id);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic struct attribute *w1_slave_attrs[] = {
1088c2ecf20Sopenharmony_ci	&dev_attr_name.attr,
1098c2ecf20Sopenharmony_ci	&dev_attr_id.attr,
1108c2ecf20Sopenharmony_ci	NULL,
1118c2ecf20Sopenharmony_ci};
1128c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(w1_slave);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/* Default family */
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_cistatic ssize_t rw_write(struct file *filp, struct kobject *kobj,
1178c2ecf20Sopenharmony_ci			struct bin_attribute *bin_attr, char *buf, loff_t off,
1188c2ecf20Sopenharmony_ci			size_t count)
1198c2ecf20Sopenharmony_ci{
1208c2ecf20Sopenharmony_ci	struct w1_slave *sl = kobj_to_w1_slave(kobj);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	mutex_lock(&sl->master->mutex);
1238c2ecf20Sopenharmony_ci	if (w1_reset_select_slave(sl)) {
1248c2ecf20Sopenharmony_ci		count = 0;
1258c2ecf20Sopenharmony_ci		goto out_up;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	w1_write_block(sl->master, buf, count);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ciout_up:
1318c2ecf20Sopenharmony_ci	mutex_unlock(&sl->master->mutex);
1328c2ecf20Sopenharmony_ci	return count;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic ssize_t rw_read(struct file *filp, struct kobject *kobj,
1368c2ecf20Sopenharmony_ci		       struct bin_attribute *bin_attr, char *buf, loff_t off,
1378c2ecf20Sopenharmony_ci		       size_t count)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct w1_slave *sl = kobj_to_w1_slave(kobj);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	mutex_lock(&sl->master->mutex);
1428c2ecf20Sopenharmony_ci	w1_read_block(sl->master, buf, count);
1438c2ecf20Sopenharmony_ci	mutex_unlock(&sl->master->mutex);
1448c2ecf20Sopenharmony_ci	return count;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic BIN_ATTR_RW(rw, PAGE_SIZE);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic struct bin_attribute *w1_slave_bin_attrs[] = {
1508c2ecf20Sopenharmony_ci	&bin_attr_rw,
1518c2ecf20Sopenharmony_ci	NULL,
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic const struct attribute_group w1_slave_default_group = {
1558c2ecf20Sopenharmony_ci	.bin_attrs = w1_slave_bin_attrs,
1568c2ecf20Sopenharmony_ci};
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic const struct attribute_group *w1_slave_default_groups[] = {
1598c2ecf20Sopenharmony_ci	&w1_slave_default_group,
1608c2ecf20Sopenharmony_ci	NULL,
1618c2ecf20Sopenharmony_ci};
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_cistatic const struct w1_family_ops w1_default_fops = {
1648c2ecf20Sopenharmony_ci	.groups		= w1_slave_default_groups,
1658c2ecf20Sopenharmony_ci};
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic struct w1_family w1_default_family = {
1688c2ecf20Sopenharmony_ci	.fops = &w1_default_fops,
1698c2ecf20Sopenharmony_ci};
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic struct bus_type w1_bus_type = {
1748c2ecf20Sopenharmony_ci	.name = "w1",
1758c2ecf20Sopenharmony_ci	.match = w1_master_match,
1768c2ecf20Sopenharmony_ci	.uevent = w1_uevent,
1778c2ecf20Sopenharmony_ci};
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_cistruct device_driver w1_master_driver = {
1808c2ecf20Sopenharmony_ci	.name = "w1_master_driver",
1818c2ecf20Sopenharmony_ci	.bus = &w1_bus_type,
1828c2ecf20Sopenharmony_ci	.probe = w1_master_probe,
1838c2ecf20Sopenharmony_ci};
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistruct device w1_master_device = {
1868c2ecf20Sopenharmony_ci	.parent = NULL,
1878c2ecf20Sopenharmony_ci	.bus = &w1_bus_type,
1888c2ecf20Sopenharmony_ci	.init_name = "w1 bus master",
1898c2ecf20Sopenharmony_ci	.driver = &w1_master_driver,
1908c2ecf20Sopenharmony_ci	.release = &w1_master_release
1918c2ecf20Sopenharmony_ci};
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_cistatic struct device_driver w1_slave_driver = {
1948c2ecf20Sopenharmony_ci	.name = "w1_slave_driver",
1958c2ecf20Sopenharmony_ci	.bus = &w1_bus_type,
1968c2ecf20Sopenharmony_ci};
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci#if 0
1998c2ecf20Sopenharmony_cistruct device w1_slave_device = {
2008c2ecf20Sopenharmony_ci	.parent = NULL,
2018c2ecf20Sopenharmony_ci	.bus = &w1_bus_type,
2028c2ecf20Sopenharmony_ci	.init_name = "w1 bus slave",
2038c2ecf20Sopenharmony_ci	.driver = &w1_slave_driver,
2048c2ecf20Sopenharmony_ci	.release = &w1_slave_release
2058c2ecf20Sopenharmony_ci};
2068c2ecf20Sopenharmony_ci#endif  /*  0  */
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2118c2ecf20Sopenharmony_ci	ssize_t count;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2148c2ecf20Sopenharmony_ci	count = sprintf(buf, "%s\n", md->name);
2158c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	return count;
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_store_search(struct device * dev,
2218c2ecf20Sopenharmony_ci						struct device_attribute *attr,
2228c2ecf20Sopenharmony_ci						const char * buf, size_t count)
2238c2ecf20Sopenharmony_ci{
2248c2ecf20Sopenharmony_ci	long tmp;
2258c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2268c2ecf20Sopenharmony_ci	int ret;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 0, &tmp);
2298c2ecf20Sopenharmony_ci	if (ret)
2308c2ecf20Sopenharmony_ci		return ret;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2338c2ecf20Sopenharmony_ci	md->search_count = tmp;
2348c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2358c2ecf20Sopenharmony_ci	/* Only wake if it is going to be searching. */
2368c2ecf20Sopenharmony_ci	if (tmp)
2378c2ecf20Sopenharmony_ci		wake_up_process(md->thread);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return count;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_search(struct device *dev,
2438c2ecf20Sopenharmony_ci					       struct device_attribute *attr,
2448c2ecf20Sopenharmony_ci					       char *buf)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2478c2ecf20Sopenharmony_ci	ssize_t count;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2508c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", md->search_count);
2518c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return count;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_store_pullup(struct device *dev,
2578c2ecf20Sopenharmony_ci						struct device_attribute *attr,
2588c2ecf20Sopenharmony_ci						const char *buf, size_t count)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	long tmp;
2618c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2628c2ecf20Sopenharmony_ci	int ret;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	ret = kstrtol(buf, 0, &tmp);
2658c2ecf20Sopenharmony_ci	if (ret)
2668c2ecf20Sopenharmony_ci		return ret;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2698c2ecf20Sopenharmony_ci	md->enable_pullup = tmp;
2708c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	return count;
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_pullup(struct device *dev,
2768c2ecf20Sopenharmony_ci					       struct device_attribute *attr,
2778c2ecf20Sopenharmony_ci					       char *buf)
2788c2ecf20Sopenharmony_ci{
2798c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2808c2ecf20Sopenharmony_ci	ssize_t count;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2838c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", md->enable_pullup);
2848c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return count;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
2928c2ecf20Sopenharmony_ci	ssize_t count;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
2958c2ecf20Sopenharmony_ci	count = sprintf(buf, "0x%p\n", md->bus_master);
2968c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
2978c2ecf20Sopenharmony_ci	return count;
2988c2ecf20Sopenharmony_ci}
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	ssize_t count;
3038c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", w1_timeout);
3048c2ecf20Sopenharmony_ci	return count;
3058c2ecf20Sopenharmony_ci}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_timeout_us(struct device *dev,
3088c2ecf20Sopenharmony_ci	struct device_attribute *attr, char *buf)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	ssize_t count;
3118c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", w1_timeout_us);
3128c2ecf20Sopenharmony_ci	return count;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
3168c2ecf20Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
3178c2ecf20Sopenharmony_ci{
3188c2ecf20Sopenharmony_ci	int tmp;
3198c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if (kstrtoint(buf, 0, &tmp) || tmp < 1)
3228c2ecf20Sopenharmony_ci		return -EINVAL;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
3258c2ecf20Sopenharmony_ci	md->max_slave_count = tmp;
3268c2ecf20Sopenharmony_ci	/* allow each time the max_slave_count is updated */
3278c2ecf20Sopenharmony_ci	clear_bit(W1_WARN_MAX_COUNT, &md->flags);
3288c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	return count;
3318c2ecf20Sopenharmony_ci}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
3348c2ecf20Sopenharmony_ci{
3358c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
3368c2ecf20Sopenharmony_ci	ssize_t count;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
3398c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", md->max_slave_count);
3408c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
3418c2ecf20Sopenharmony_ci	return count;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
3478c2ecf20Sopenharmony_ci	ssize_t count;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
3508c2ecf20Sopenharmony_ci	count = sprintf(buf, "%lu\n", md->attempts);
3518c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
3528c2ecf20Sopenharmony_ci	return count;
3538c2ecf20Sopenharmony_ci}
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
3588c2ecf20Sopenharmony_ci	ssize_t count;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
3618c2ecf20Sopenharmony_ci	count = sprintf(buf, "%d\n", md->slave_count);
3628c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
3638c2ecf20Sopenharmony_ci	return count;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_slaves(struct device *dev,
3678c2ecf20Sopenharmony_ci	struct device_attribute *attr, char *buf)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
3708c2ecf20Sopenharmony_ci	int c = PAGE_SIZE;
3718c2ecf20Sopenharmony_ci	struct list_head *ent, *n;
3728c2ecf20Sopenharmony_ci	struct w1_slave *sl = NULL;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	mutex_lock(&md->list_mutex);
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	list_for_each_safe(ent, n, &md->slist) {
3778c2ecf20Sopenharmony_ci		sl = list_entry(ent, struct w1_slave, w1_slave_entry);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci		c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
3808c2ecf20Sopenharmony_ci	}
3818c2ecf20Sopenharmony_ci	if (!sl)
3828c2ecf20Sopenharmony_ci		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	mutex_unlock(&md->list_mutex);
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return PAGE_SIZE - c;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_add(struct device *dev,
3908c2ecf20Sopenharmony_ci	struct device_attribute *attr, char *buf)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int c = PAGE_SIZE;
3938c2ecf20Sopenharmony_ci	c -= snprintf(buf+PAGE_SIZE - c, c,
3948c2ecf20Sopenharmony_ci		"write device id xx-xxxxxxxxxxxx to add slave\n");
3958c2ecf20Sopenharmony_ci	return PAGE_SIZE - c;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
3998c2ecf20Sopenharmony_ci	struct w1_reg_num *rn)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	unsigned int family;
4028c2ecf20Sopenharmony_ci	unsigned long long id;
4038c2ecf20Sopenharmony_ci	int i;
4048c2ecf20Sopenharmony_ci	u64 rn64_le;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	/* The CRC value isn't read from the user because the sysfs directory
4078c2ecf20Sopenharmony_ci	 * doesn't include it and most messages from the bus search don't
4088c2ecf20Sopenharmony_ci	 * print it either.  It would be unreasonable for the user to then
4098c2ecf20Sopenharmony_ci	 * provide it.
4108c2ecf20Sopenharmony_ci	 */
4118c2ecf20Sopenharmony_ci	const char *error_msg = "bad slave string format, expecting "
4128c2ecf20Sopenharmony_ci		"ff-dddddddddddd\n";
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	if (buf[2] != '-') {
4158c2ecf20Sopenharmony_ci		dev_err(dev, "%s", error_msg);
4168c2ecf20Sopenharmony_ci		return -EINVAL;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	i = sscanf(buf, "%02x-%012llx", &family, &id);
4198c2ecf20Sopenharmony_ci	if (i != 2) {
4208c2ecf20Sopenharmony_ci		dev_err(dev, "%s", error_msg);
4218c2ecf20Sopenharmony_ci		return -EINVAL;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	rn->family = family;
4248c2ecf20Sopenharmony_ci	rn->id = id;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	rn64_le = cpu_to_le64(*(u64 *)rn);
4278c2ecf20Sopenharmony_ci	rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci#if 0
4308c2ecf20Sopenharmony_ci	dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
4318c2ecf20Sopenharmony_ci		  rn->family, (unsigned long long)rn->id, rn->crc);
4328c2ecf20Sopenharmony_ci#endif
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	return 0;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci/* Searches the slaves in the w1_master and returns a pointer or NULL.
4388c2ecf20Sopenharmony_ci * Note: must not hold list_mutex
4398c2ecf20Sopenharmony_ci */
4408c2ecf20Sopenharmony_cistruct w1_slave *w1_slave_search_device(struct w1_master *dev,
4418c2ecf20Sopenharmony_ci	struct w1_reg_num *rn)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct w1_slave *sl;
4448c2ecf20Sopenharmony_ci	mutex_lock(&dev->list_mutex);
4458c2ecf20Sopenharmony_ci	list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
4468c2ecf20Sopenharmony_ci		if (sl->reg_num.family == rn->family &&
4478c2ecf20Sopenharmony_ci				sl->reg_num.id == rn->id &&
4488c2ecf20Sopenharmony_ci				sl->reg_num.crc == rn->crc) {
4498c2ecf20Sopenharmony_ci			mutex_unlock(&dev->list_mutex);
4508c2ecf20Sopenharmony_ci			return sl;
4518c2ecf20Sopenharmony_ci		}
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci	mutex_unlock(&dev->list_mutex);
4548c2ecf20Sopenharmony_ci	return NULL;
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_store_add(struct device *dev,
4588c2ecf20Sopenharmony_ci						struct device_attribute *attr,
4598c2ecf20Sopenharmony_ci						const char *buf, size_t count)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
4628c2ecf20Sopenharmony_ci	struct w1_reg_num rn;
4638c2ecf20Sopenharmony_ci	struct w1_slave *sl;
4648c2ecf20Sopenharmony_ci	ssize_t result = count;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	if (w1_atoreg_num(dev, buf, count, &rn))
4678c2ecf20Sopenharmony_ci		return -EINVAL;
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
4708c2ecf20Sopenharmony_ci	sl = w1_slave_search_device(md, &rn);
4718c2ecf20Sopenharmony_ci	/* It would be nice to do a targeted search one the one-wire bus
4728c2ecf20Sopenharmony_ci	 * for the new device to see if it is out there or not.  But the
4738c2ecf20Sopenharmony_ci	 * current search doesn't support that.
4748c2ecf20Sopenharmony_ci	 */
4758c2ecf20Sopenharmony_ci	if (sl) {
4768c2ecf20Sopenharmony_ci		dev_info(dev, "Device %s already exists\n", sl->name);
4778c2ecf20Sopenharmony_ci		result = -EINVAL;
4788c2ecf20Sopenharmony_ci	} else {
4798c2ecf20Sopenharmony_ci		w1_attach_slave_device(md, &rn);
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return result;
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_show_remove(struct device *dev,
4878c2ecf20Sopenharmony_ci	struct device_attribute *attr, char *buf)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	int c = PAGE_SIZE;
4908c2ecf20Sopenharmony_ci	c -= snprintf(buf+PAGE_SIZE - c, c,
4918c2ecf20Sopenharmony_ci		"write device id xx-xxxxxxxxxxxx to remove slave\n");
4928c2ecf20Sopenharmony_ci	return PAGE_SIZE - c;
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic ssize_t w1_master_attribute_store_remove(struct device *dev,
4968c2ecf20Sopenharmony_ci						struct device_attribute *attr,
4978c2ecf20Sopenharmony_ci						const char *buf, size_t count)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct w1_master *md = dev_to_w1_master(dev);
5008c2ecf20Sopenharmony_ci	struct w1_reg_num rn;
5018c2ecf20Sopenharmony_ci	struct w1_slave *sl;
5028c2ecf20Sopenharmony_ci	ssize_t result = count;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (w1_atoreg_num(dev, buf, count, &rn))
5058c2ecf20Sopenharmony_ci		return -EINVAL;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	mutex_lock(&md->mutex);
5088c2ecf20Sopenharmony_ci	sl = w1_slave_search_device(md, &rn);
5098c2ecf20Sopenharmony_ci	if (sl) {
5108c2ecf20Sopenharmony_ci		result = w1_slave_detach(sl);
5118c2ecf20Sopenharmony_ci		/* refcnt 0 means it was detached in the call */
5128c2ecf20Sopenharmony_ci		if (result == 0)
5138c2ecf20Sopenharmony_ci			result = count;
5148c2ecf20Sopenharmony_ci	} else {
5158c2ecf20Sopenharmony_ci		dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
5168c2ecf20Sopenharmony_ci			(unsigned long long)rn.id);
5178c2ecf20Sopenharmony_ci		result = -EINVAL;
5188c2ecf20Sopenharmony_ci	}
5198c2ecf20Sopenharmony_ci	mutex_unlock(&md->mutex);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	return result;
5228c2ecf20Sopenharmony_ci}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci#define W1_MASTER_ATTR_RO(_name, _mode)				\
5258c2ecf20Sopenharmony_ci	struct device_attribute w1_master_attribute_##_name =	\
5268c2ecf20Sopenharmony_ci		__ATTR(w1_master_##_name, _mode,		\
5278c2ecf20Sopenharmony_ci		       w1_master_attribute_show_##_name, NULL)
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci#define W1_MASTER_ATTR_RW(_name, _mode)				\
5308c2ecf20Sopenharmony_ci	struct device_attribute w1_master_attribute_##_name =	\
5318c2ecf20Sopenharmony_ci		__ATTR(w1_master_##_name, _mode,		\
5328c2ecf20Sopenharmony_ci		       w1_master_attribute_show_##_name,	\
5338c2ecf20Sopenharmony_ci		       w1_master_attribute_store_##_name)
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(name, S_IRUGO);
5368c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(slaves, S_IRUGO);
5378c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
5388c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
5398c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(attempts, S_IRUGO);
5408c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(timeout, S_IRUGO);
5418c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(timeout_us, S_IRUGO);
5428c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RO(pointer, S_IRUGO);
5438c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP);
5448c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP);
5458c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP);
5468c2ecf20Sopenharmony_cistatic W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic struct attribute *w1_master_default_attrs[] = {
5498c2ecf20Sopenharmony_ci	&w1_master_attribute_name.attr,
5508c2ecf20Sopenharmony_ci	&w1_master_attribute_slaves.attr,
5518c2ecf20Sopenharmony_ci	&w1_master_attribute_slave_count.attr,
5528c2ecf20Sopenharmony_ci	&w1_master_attribute_max_slave_count.attr,
5538c2ecf20Sopenharmony_ci	&w1_master_attribute_attempts.attr,
5548c2ecf20Sopenharmony_ci	&w1_master_attribute_timeout.attr,
5558c2ecf20Sopenharmony_ci	&w1_master_attribute_timeout_us.attr,
5568c2ecf20Sopenharmony_ci	&w1_master_attribute_pointer.attr,
5578c2ecf20Sopenharmony_ci	&w1_master_attribute_search.attr,
5588c2ecf20Sopenharmony_ci	&w1_master_attribute_pullup.attr,
5598c2ecf20Sopenharmony_ci	&w1_master_attribute_add.attr,
5608c2ecf20Sopenharmony_ci	&w1_master_attribute_remove.attr,
5618c2ecf20Sopenharmony_ci	NULL
5628c2ecf20Sopenharmony_ci};
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic const struct attribute_group w1_master_defattr_group = {
5658c2ecf20Sopenharmony_ci	.attrs = w1_master_default_attrs,
5668c2ecf20Sopenharmony_ci};
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ciint w1_create_master_attributes(struct w1_master *master)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
5718c2ecf20Sopenharmony_ci}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_civoid w1_destroy_master_attributes(struct w1_master *master)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
5768c2ecf20Sopenharmony_ci}
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	struct w1_master *md = NULL;
5818c2ecf20Sopenharmony_ci	struct w1_slave *sl = NULL;
5828c2ecf20Sopenharmony_ci	char *event_owner, *name;
5838c2ecf20Sopenharmony_ci	int err = 0;
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (dev->driver == &w1_master_driver) {
5868c2ecf20Sopenharmony_ci		md = container_of(dev, struct w1_master, dev);
5878c2ecf20Sopenharmony_ci		event_owner = "master";
5888c2ecf20Sopenharmony_ci		name = md->name;
5898c2ecf20Sopenharmony_ci	} else if (dev->driver == &w1_slave_driver) {
5908c2ecf20Sopenharmony_ci		sl = container_of(dev, struct w1_slave, dev);
5918c2ecf20Sopenharmony_ci		event_owner = "slave";
5928c2ecf20Sopenharmony_ci		name = sl->name;
5938c2ecf20Sopenharmony_ci	} else {
5948c2ecf20Sopenharmony_ci		dev_dbg(dev, "Unknown event.\n");
5958c2ecf20Sopenharmony_ci		return -EINVAL;
5968c2ecf20Sopenharmony_ci	}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n",
5998c2ecf20Sopenharmony_ci			event_owner, name, dev_name(dev));
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	if (dev->driver != &w1_slave_driver || !sl)
6028c2ecf20Sopenharmony_ci		goto end;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
6058c2ecf20Sopenharmony_ci	if (err)
6068c2ecf20Sopenharmony_ci		goto end;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
6098c2ecf20Sopenharmony_ci			     (unsigned long long)sl->reg_num.id);
6108c2ecf20Sopenharmony_ciend:
6118c2ecf20Sopenharmony_ci	return err;
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cistatic int w1_family_notify(unsigned long action, struct w1_slave *sl)
6158c2ecf20Sopenharmony_ci{
6168c2ecf20Sopenharmony_ci	const struct w1_family_ops *fops;
6178c2ecf20Sopenharmony_ci	int err;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	fops = sl->family->fops;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	if (!fops)
6228c2ecf20Sopenharmony_ci		return 0;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	switch (action) {
6258c2ecf20Sopenharmony_ci	case BUS_NOTIFY_ADD_DEVICE:
6268c2ecf20Sopenharmony_ci		/* if the family driver needs to initialize something... */
6278c2ecf20Sopenharmony_ci		if (fops->add_slave) {
6288c2ecf20Sopenharmony_ci			err = fops->add_slave(sl);
6298c2ecf20Sopenharmony_ci			if (err < 0) {
6308c2ecf20Sopenharmony_ci				dev_err(&sl->dev,
6318c2ecf20Sopenharmony_ci					"add_slave() call failed. err=%d\n",
6328c2ecf20Sopenharmony_ci					err);
6338c2ecf20Sopenharmony_ci				return err;
6348c2ecf20Sopenharmony_ci			}
6358c2ecf20Sopenharmony_ci		}
6368c2ecf20Sopenharmony_ci		if (fops->groups) {
6378c2ecf20Sopenharmony_ci			err = sysfs_create_groups(&sl->dev.kobj, fops->groups);
6388c2ecf20Sopenharmony_ci			if (err) {
6398c2ecf20Sopenharmony_ci				dev_err(&sl->dev,
6408c2ecf20Sopenharmony_ci					"sysfs group creation failed. err=%d\n",
6418c2ecf20Sopenharmony_ci					err);
6428c2ecf20Sopenharmony_ci				return err;
6438c2ecf20Sopenharmony_ci			}
6448c2ecf20Sopenharmony_ci		}
6458c2ecf20Sopenharmony_ci		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info) {
6468c2ecf20Sopenharmony_ci			struct device *hwmon
6478c2ecf20Sopenharmony_ci				= hwmon_device_register_with_info(&sl->dev,
6488c2ecf20Sopenharmony_ci						"w1_slave_temp", sl,
6498c2ecf20Sopenharmony_ci						fops->chip_info,
6508c2ecf20Sopenharmony_ci						NULL);
6518c2ecf20Sopenharmony_ci			if (IS_ERR(hwmon)) {
6528c2ecf20Sopenharmony_ci				dev_warn(&sl->dev,
6538c2ecf20Sopenharmony_ci					 "could not create hwmon device\n");
6548c2ecf20Sopenharmony_ci			} else {
6558c2ecf20Sopenharmony_ci				sl->hwmon = hwmon;
6568c2ecf20Sopenharmony_ci			}
6578c2ecf20Sopenharmony_ci		}
6588c2ecf20Sopenharmony_ci		break;
6598c2ecf20Sopenharmony_ci	case BUS_NOTIFY_DEL_DEVICE:
6608c2ecf20Sopenharmony_ci		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info &&
6618c2ecf20Sopenharmony_ci			    sl->hwmon)
6628c2ecf20Sopenharmony_ci			hwmon_device_unregister(sl->hwmon);
6638c2ecf20Sopenharmony_ci		if (fops->remove_slave)
6648c2ecf20Sopenharmony_ci			sl->family->fops->remove_slave(sl);
6658c2ecf20Sopenharmony_ci		if (fops->groups)
6668c2ecf20Sopenharmony_ci			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
6678c2ecf20Sopenharmony_ci		break;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci	return 0;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int __w1_attach_slave_device(struct w1_slave *sl)
6738c2ecf20Sopenharmony_ci{
6748c2ecf20Sopenharmony_ci	int err;
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_ci	sl->dev.parent = &sl->master->dev;
6778c2ecf20Sopenharmony_ci	sl->dev.driver = &w1_slave_driver;
6788c2ecf20Sopenharmony_ci	sl->dev.bus = &w1_bus_type;
6798c2ecf20Sopenharmony_ci	sl->dev.release = &w1_slave_release;
6808c2ecf20Sopenharmony_ci	sl->dev.groups = w1_slave_groups;
6818c2ecf20Sopenharmony_ci	sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node,
6828c2ecf20Sopenharmony_ci						sl->family->of_match_table);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	dev_set_name(&sl->dev, "%02x-%012llx",
6858c2ecf20Sopenharmony_ci		 (unsigned int) sl->reg_num.family,
6868c2ecf20Sopenharmony_ci		 (unsigned long long) sl->reg_num.id);
6878c2ecf20Sopenharmony_ci	snprintf(&sl->name[0], sizeof(sl->name),
6888c2ecf20Sopenharmony_ci		 "%02x-%012llx",
6898c2ecf20Sopenharmony_ci		 (unsigned int) sl->reg_num.family,
6908c2ecf20Sopenharmony_ci		 (unsigned long long) sl->reg_num.id);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
6938c2ecf20Sopenharmony_ci		dev_name(&sl->dev), sl);
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_ci	/* suppress for w1_family_notify before sending KOBJ_ADD */
6968c2ecf20Sopenharmony_ci	dev_set_uevent_suppress(&sl->dev, true);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	err = device_register(&sl->dev);
6998c2ecf20Sopenharmony_ci	if (err < 0) {
7008c2ecf20Sopenharmony_ci		dev_err(&sl->dev,
7018c2ecf20Sopenharmony_ci			"Device registration [%s] failed. err=%d\n",
7028c2ecf20Sopenharmony_ci			dev_name(&sl->dev), err);
7038c2ecf20Sopenharmony_ci		put_device(&sl->dev);
7048c2ecf20Sopenharmony_ci		return err;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci	w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	dev_set_uevent_suppress(&sl->dev, false);
7098c2ecf20Sopenharmony_ci	kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	mutex_lock(&sl->master->list_mutex);
7128c2ecf20Sopenharmony_ci	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
7138c2ecf20Sopenharmony_ci	mutex_unlock(&sl->master->list_mutex);
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	return 0;
7168c2ecf20Sopenharmony_ci}
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ciint w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
7198c2ecf20Sopenharmony_ci{
7208c2ecf20Sopenharmony_ci	struct w1_slave *sl;
7218c2ecf20Sopenharmony_ci	struct w1_family *f;
7228c2ecf20Sopenharmony_ci	int err;
7238c2ecf20Sopenharmony_ci	struct w1_netlink_msg msg;
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
7268c2ecf20Sopenharmony_ci	if (!sl) {
7278c2ecf20Sopenharmony_ci		dev_err(&dev->dev,
7288c2ecf20Sopenharmony_ci			 "%s: failed to allocate new slave device.\n",
7298c2ecf20Sopenharmony_ci			 __func__);
7308c2ecf20Sopenharmony_ci		return -ENOMEM;
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	sl->owner = THIS_MODULE;
7358c2ecf20Sopenharmony_ci	sl->master = dev;
7368c2ecf20Sopenharmony_ci	set_bit(W1_SLAVE_ACTIVE, &sl->flags);
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	memset(&msg, 0, sizeof(msg));
7398c2ecf20Sopenharmony_ci	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
7408c2ecf20Sopenharmony_ci	atomic_set(&sl->refcnt, 1);
7418c2ecf20Sopenharmony_ci	atomic_inc(&sl->master->refcnt);
7428c2ecf20Sopenharmony_ci	dev->slave_count++;
7438c2ecf20Sopenharmony_ci	dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n",
7448c2ecf20Sopenharmony_ci		  rn->family, (unsigned long long)rn->id, rn->crc);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	/* slave modules need to be loaded in a context with unlocked mutex */
7478c2ecf20Sopenharmony_ci	mutex_unlock(&dev->mutex);
7488c2ecf20Sopenharmony_ci	request_module("w1-family-0x%02X", rn->family);
7498c2ecf20Sopenharmony_ci	mutex_lock(&dev->mutex);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	spin_lock(&w1_flock);
7528c2ecf20Sopenharmony_ci	f = w1_family_registered(rn->family);
7538c2ecf20Sopenharmony_ci	if (!f) {
7548c2ecf20Sopenharmony_ci		f= &w1_default_family;
7558c2ecf20Sopenharmony_ci		dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
7568c2ecf20Sopenharmony_ci			  rn->family, rn->family,
7578c2ecf20Sopenharmony_ci			  (unsigned long long)rn->id, rn->crc);
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci	__w1_family_get(f);
7608c2ecf20Sopenharmony_ci	spin_unlock(&w1_flock);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	sl->family = f;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	err = __w1_attach_slave_device(sl);
7658c2ecf20Sopenharmony_ci	if (err < 0) {
7668c2ecf20Sopenharmony_ci		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
7678c2ecf20Sopenharmony_ci			 sl->name);
7688c2ecf20Sopenharmony_ci		dev->slave_count--;
7698c2ecf20Sopenharmony_ci		w1_family_put(sl->family);
7708c2ecf20Sopenharmony_ci		atomic_dec(&sl->master->refcnt);
7718c2ecf20Sopenharmony_ci		kfree(sl);
7728c2ecf20Sopenharmony_ci		return err;
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	sl->ttl = dev->slave_ttl;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	memcpy(msg.id.id, rn, sizeof(msg.id));
7788c2ecf20Sopenharmony_ci	msg.type = W1_SLAVE_ADD;
7798c2ecf20Sopenharmony_ci	w1_netlink_send(dev, &msg);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	return 0;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ciint w1_unref_slave(struct w1_slave *sl)
7858c2ecf20Sopenharmony_ci{
7868c2ecf20Sopenharmony_ci	struct w1_master *dev = sl->master;
7878c2ecf20Sopenharmony_ci	int refcnt;
7888c2ecf20Sopenharmony_ci	mutex_lock(&dev->list_mutex);
7898c2ecf20Sopenharmony_ci	refcnt = atomic_sub_return(1, &sl->refcnt);
7908c2ecf20Sopenharmony_ci	if (refcnt == 0) {
7918c2ecf20Sopenharmony_ci		struct w1_netlink_msg msg;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci		dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
7948c2ecf20Sopenharmony_ci			sl->name, sl);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci		list_del(&sl->w1_slave_entry);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci		memset(&msg, 0, sizeof(msg));
7998c2ecf20Sopenharmony_ci		memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
8008c2ecf20Sopenharmony_ci		msg.type = W1_SLAVE_REMOVE;
8018c2ecf20Sopenharmony_ci		w1_netlink_send(sl->master, &msg);
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl);
8048c2ecf20Sopenharmony_ci		device_unregister(&sl->dev);
8058c2ecf20Sopenharmony_ci		#ifdef DEBUG
8068c2ecf20Sopenharmony_ci		memset(sl, 0, sizeof(*sl));
8078c2ecf20Sopenharmony_ci		#endif
8088c2ecf20Sopenharmony_ci		kfree(sl);
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci	atomic_dec(&dev->refcnt);
8118c2ecf20Sopenharmony_ci	mutex_unlock(&dev->list_mutex);
8128c2ecf20Sopenharmony_ci	return refcnt;
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ciint w1_slave_detach(struct w1_slave *sl)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci	/* Only detach a slave once as it decreases the refcnt each time. */
8188c2ecf20Sopenharmony_ci	int destroy_now;
8198c2ecf20Sopenharmony_ci	mutex_lock(&sl->master->list_mutex);
8208c2ecf20Sopenharmony_ci	destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags);
8218c2ecf20Sopenharmony_ci	set_bit(W1_SLAVE_DETACH, &sl->flags);
8228c2ecf20Sopenharmony_ci	mutex_unlock(&sl->master->list_mutex);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (destroy_now)
8258c2ecf20Sopenharmony_ci		destroy_now = !w1_unref_slave(sl);
8268c2ecf20Sopenharmony_ci	return destroy_now ? 0 : -EBUSY;
8278c2ecf20Sopenharmony_ci}
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_cistruct w1_master *w1_search_master_id(u32 id)
8308c2ecf20Sopenharmony_ci{
8318c2ecf20Sopenharmony_ci	struct w1_master *dev;
8328c2ecf20Sopenharmony_ci	int found = 0;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	mutex_lock(&w1_mlock);
8358c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
8368c2ecf20Sopenharmony_ci		if (dev->id == id) {
8378c2ecf20Sopenharmony_ci			found = 1;
8388c2ecf20Sopenharmony_ci			atomic_inc(&dev->refcnt);
8398c2ecf20Sopenharmony_ci			break;
8408c2ecf20Sopenharmony_ci		}
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci	mutex_unlock(&w1_mlock);
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return (found)?dev:NULL;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_cistruct w1_slave *w1_search_slave(struct w1_reg_num *id)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	struct w1_master *dev;
8508c2ecf20Sopenharmony_ci	struct w1_slave *sl = NULL;
8518c2ecf20Sopenharmony_ci	int found = 0;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	mutex_lock(&w1_mlock);
8548c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
8558c2ecf20Sopenharmony_ci		mutex_lock(&dev->list_mutex);
8568c2ecf20Sopenharmony_ci		list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
8578c2ecf20Sopenharmony_ci			if (sl->reg_num.family == id->family &&
8588c2ecf20Sopenharmony_ci					sl->reg_num.id == id->id &&
8598c2ecf20Sopenharmony_ci					sl->reg_num.crc == id->crc) {
8608c2ecf20Sopenharmony_ci				found = 1;
8618c2ecf20Sopenharmony_ci				atomic_inc(&dev->refcnt);
8628c2ecf20Sopenharmony_ci				atomic_inc(&sl->refcnt);
8638c2ecf20Sopenharmony_ci				break;
8648c2ecf20Sopenharmony_ci			}
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci		mutex_unlock(&dev->list_mutex);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci		if (found)
8698c2ecf20Sopenharmony_ci			break;
8708c2ecf20Sopenharmony_ci	}
8718c2ecf20Sopenharmony_ci	mutex_unlock(&w1_mlock);
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci	return (found)?sl:NULL;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_civoid w1_reconnect_slaves(struct w1_family *f, int attach)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct w1_slave *sl, *sln;
8798c2ecf20Sopenharmony_ci	struct w1_master *dev;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	mutex_lock(&w1_mlock);
8828c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
8838c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
8848c2ecf20Sopenharmony_ci			"for family %02x.\n", dev->name, f->fid);
8858c2ecf20Sopenharmony_ci		mutex_lock(&dev->mutex);
8868c2ecf20Sopenharmony_ci		mutex_lock(&dev->list_mutex);
8878c2ecf20Sopenharmony_ci		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
8888c2ecf20Sopenharmony_ci			/* If it is a new family, slaves with the default
8898c2ecf20Sopenharmony_ci			 * family driver and are that family will be
8908c2ecf20Sopenharmony_ci			 * connected.  If the family is going away, devices
8918c2ecf20Sopenharmony_ci			 * matching that family are reconneced.
8928c2ecf20Sopenharmony_ci			 */
8938c2ecf20Sopenharmony_ci			if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
8948c2ecf20Sopenharmony_ci				&& sl->reg_num.family == f->fid) ||
8958c2ecf20Sopenharmony_ci				(!attach && sl->family->fid == f->fid)) {
8968c2ecf20Sopenharmony_ci				struct w1_reg_num rn;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci				mutex_unlock(&dev->list_mutex);
8998c2ecf20Sopenharmony_ci				memcpy(&rn, &sl->reg_num, sizeof(rn));
9008c2ecf20Sopenharmony_ci				/* If it was already in use let the automatic
9018c2ecf20Sopenharmony_ci				 * scan pick it up again later.
9028c2ecf20Sopenharmony_ci				 */
9038c2ecf20Sopenharmony_ci				if (!w1_slave_detach(sl))
9048c2ecf20Sopenharmony_ci					w1_attach_slave_device(dev, &rn);
9058c2ecf20Sopenharmony_ci				mutex_lock(&dev->list_mutex);
9068c2ecf20Sopenharmony_ci			}
9078c2ecf20Sopenharmony_ci		}
9088c2ecf20Sopenharmony_ci		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
9098c2ecf20Sopenharmony_ci			"has been finished.\n", dev->name);
9108c2ecf20Sopenharmony_ci		mutex_unlock(&dev->list_mutex);
9118c2ecf20Sopenharmony_ci		mutex_unlock(&dev->mutex);
9128c2ecf20Sopenharmony_ci	}
9138c2ecf20Sopenharmony_ci	mutex_unlock(&w1_mlock);
9148c2ecf20Sopenharmony_ci}
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_civoid w1_slave_found(struct w1_master *dev, u64 rn)
9178c2ecf20Sopenharmony_ci{
9188c2ecf20Sopenharmony_ci	struct w1_slave *sl;
9198c2ecf20Sopenharmony_ci	struct w1_reg_num *tmp;
9208c2ecf20Sopenharmony_ci	u64 rn_le = cpu_to_le64(rn);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	atomic_inc(&dev->refcnt);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	tmp = (struct w1_reg_num *) &rn;
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	sl = w1_slave_search_device(dev, tmp);
9278c2ecf20Sopenharmony_ci	if (sl) {
9288c2ecf20Sopenharmony_ci		set_bit(W1_SLAVE_ACTIVE, &sl->flags);
9298c2ecf20Sopenharmony_ci	} else {
9308c2ecf20Sopenharmony_ci		if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7))
9318c2ecf20Sopenharmony_ci			w1_attach_slave_device(dev, tmp);
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ci	atomic_dec(&dev->refcnt);
9358c2ecf20Sopenharmony_ci}
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci/**
9388c2ecf20Sopenharmony_ci * w1_search() - Performs a ROM Search & registers any devices found.
9398c2ecf20Sopenharmony_ci * @dev: The master device to search
9408c2ecf20Sopenharmony_ci * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH
9418c2ecf20Sopenharmony_ci * to return only devices in the alarmed state
9428c2ecf20Sopenharmony_ci * @cb: Function to call when a device is found
9438c2ecf20Sopenharmony_ci *
9448c2ecf20Sopenharmony_ci * The 1-wire search is a simple binary tree search.
9458c2ecf20Sopenharmony_ci * For each bit of the address, we read two bits and write one bit.
9468c2ecf20Sopenharmony_ci * The bit written will put to sleep all devies that don't match that bit.
9478c2ecf20Sopenharmony_ci * When the two reads differ, the direction choice is obvious.
9488c2ecf20Sopenharmony_ci * When both bits are 0, we must choose a path to take.
9498c2ecf20Sopenharmony_ci * When we can scan all 64 bits without having to choose a path, we are done.
9508c2ecf20Sopenharmony_ci *
9518c2ecf20Sopenharmony_ci * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
9528c2ecf20Sopenharmony_ci *
9538c2ecf20Sopenharmony_ci */
9548c2ecf20Sopenharmony_civoid w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
9558c2ecf20Sopenharmony_ci{
9568c2ecf20Sopenharmony_ci	u64 last_rn, rn, tmp64;
9578c2ecf20Sopenharmony_ci	int i, slave_count = 0;
9588c2ecf20Sopenharmony_ci	int last_zero, last_device;
9598c2ecf20Sopenharmony_ci	int search_bit, desc_bit;
9608c2ecf20Sopenharmony_ci	u8  triplet_ret = 0;
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci	search_bit = 0;
9638c2ecf20Sopenharmony_ci	rn = dev->search_id;
9648c2ecf20Sopenharmony_ci	last_rn = 0;
9658c2ecf20Sopenharmony_ci	last_device = 0;
9668c2ecf20Sopenharmony_ci	last_zero = -1;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	desc_bit = 64;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
9718c2ecf20Sopenharmony_ci		last_rn = rn;
9728c2ecf20Sopenharmony_ci		rn = 0;
9738c2ecf20Sopenharmony_ci
9748c2ecf20Sopenharmony_ci		/*
9758c2ecf20Sopenharmony_ci		 * Reset bus and all 1-wire device state machines
9768c2ecf20Sopenharmony_ci		 * so they can respond to our requests.
9778c2ecf20Sopenharmony_ci		 *
9788c2ecf20Sopenharmony_ci		 * Return 0 - device(s) present, 1 - no devices present.
9798c2ecf20Sopenharmony_ci		 */
9808c2ecf20Sopenharmony_ci		mutex_lock(&dev->bus_mutex);
9818c2ecf20Sopenharmony_ci		if (w1_reset_bus(dev)) {
9828c2ecf20Sopenharmony_ci			mutex_unlock(&dev->bus_mutex);
9838c2ecf20Sopenharmony_ci			dev_dbg(&dev->dev, "No devices present on the wire.\n");
9848c2ecf20Sopenharmony_ci			break;
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci		/* Do fast search on single slave bus */
9888c2ecf20Sopenharmony_ci		if (dev->max_slave_count == 1) {
9898c2ecf20Sopenharmony_ci			int rv;
9908c2ecf20Sopenharmony_ci			w1_write_8(dev, W1_READ_ROM);
9918c2ecf20Sopenharmony_ci			rv = w1_read_block(dev, (u8 *)&rn, 8);
9928c2ecf20Sopenharmony_ci			mutex_unlock(&dev->bus_mutex);
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci			if (rv == 8 && rn)
9958c2ecf20Sopenharmony_ci				cb(dev, rn);
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci			break;
9988c2ecf20Sopenharmony_ci		}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci		/* Start the search */
10018c2ecf20Sopenharmony_ci		w1_write_8(dev, search_type);
10028c2ecf20Sopenharmony_ci		for (i = 0; i < 64; ++i) {
10038c2ecf20Sopenharmony_ci			/* Determine the direction/search bit */
10048c2ecf20Sopenharmony_ci			if (i == desc_bit)
10058c2ecf20Sopenharmony_ci				search_bit = 1;	  /* took the 0 path last time, so take the 1 path */
10068c2ecf20Sopenharmony_ci			else if (i > desc_bit)
10078c2ecf20Sopenharmony_ci				search_bit = 0;	  /* take the 0 path on the next branch */
10088c2ecf20Sopenharmony_ci			else
10098c2ecf20Sopenharmony_ci				search_bit = ((last_rn >> i) & 0x1);
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci			/* Read two bits and write one bit */
10128c2ecf20Sopenharmony_ci			triplet_ret = w1_triplet(dev, search_bit);
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci			/* quit if no device responded */
10158c2ecf20Sopenharmony_ci			if ( (triplet_ret & 0x03) == 0x03 )
10168c2ecf20Sopenharmony_ci				break;
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_ci			/* If both directions were valid, and we took the 0 path... */
10198c2ecf20Sopenharmony_ci			if (triplet_ret == 0)
10208c2ecf20Sopenharmony_ci				last_zero = i;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci			/* extract the direction taken & update the device number */
10238c2ecf20Sopenharmony_ci			tmp64 = (triplet_ret >> 2);
10248c2ecf20Sopenharmony_ci			rn |= (tmp64 << i);
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
10278c2ecf20Sopenharmony_ci				mutex_unlock(&dev->bus_mutex);
10288c2ecf20Sopenharmony_ci				dev_dbg(&dev->dev, "Abort w1_search\n");
10298c2ecf20Sopenharmony_ci				return;
10308c2ecf20Sopenharmony_ci			}
10318c2ecf20Sopenharmony_ci		}
10328c2ecf20Sopenharmony_ci		mutex_unlock(&dev->bus_mutex);
10338c2ecf20Sopenharmony_ci
10348c2ecf20Sopenharmony_ci		if ( (triplet_ret & 0x03) != 0x03 ) {
10358c2ecf20Sopenharmony_ci			if ((desc_bit == last_zero) || (last_zero < 0)) {
10368c2ecf20Sopenharmony_ci				last_device = 1;
10378c2ecf20Sopenharmony_ci				dev->search_id = 0;
10388c2ecf20Sopenharmony_ci			} else {
10398c2ecf20Sopenharmony_ci				dev->search_id = rn;
10408c2ecf20Sopenharmony_ci			}
10418c2ecf20Sopenharmony_ci			desc_bit = last_zero;
10428c2ecf20Sopenharmony_ci			cb(dev, rn);
10438c2ecf20Sopenharmony_ci		}
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci		if (!last_device && slave_count == dev->max_slave_count &&
10468c2ecf20Sopenharmony_ci			!test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
10478c2ecf20Sopenharmony_ci			/* Only max_slave_count will be scanned in a search,
10488c2ecf20Sopenharmony_ci			 * but it will start where it left off next search
10498c2ecf20Sopenharmony_ci			 * until all ids are identified and then it will start
10508c2ecf20Sopenharmony_ci			 * over.  A continued search will report the previous
10518c2ecf20Sopenharmony_ci			 * last id as the first id (provided it is still on the
10528c2ecf20Sopenharmony_ci			 * bus).
10538c2ecf20Sopenharmony_ci			 */
10548c2ecf20Sopenharmony_ci			dev_info(&dev->dev, "%s: max_slave_count %d reached, "
10558c2ecf20Sopenharmony_ci				"will continue next search.\n", __func__,
10568c2ecf20Sopenharmony_ci				dev->max_slave_count);
10578c2ecf20Sopenharmony_ci			set_bit(W1_WARN_MAX_COUNT, &dev->flags);
10588c2ecf20Sopenharmony_ci		}
10598c2ecf20Sopenharmony_ci	}
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_civoid w1_search_process_cb(struct w1_master *dev, u8 search_type,
10638c2ecf20Sopenharmony_ci	w1_slave_found_callback cb)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	struct w1_slave *sl, *sln;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci	mutex_lock(&dev->list_mutex);
10688c2ecf20Sopenharmony_ci	list_for_each_entry(sl, &dev->slist, w1_slave_entry)
10698c2ecf20Sopenharmony_ci		clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
10708c2ecf20Sopenharmony_ci	mutex_unlock(&dev->list_mutex);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	w1_search_devices(dev, search_type, cb);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	mutex_lock(&dev->list_mutex);
10758c2ecf20Sopenharmony_ci	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
10768c2ecf20Sopenharmony_ci		if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
10778c2ecf20Sopenharmony_ci			mutex_unlock(&dev->list_mutex);
10788c2ecf20Sopenharmony_ci			w1_slave_detach(sl);
10798c2ecf20Sopenharmony_ci			mutex_lock(&dev->list_mutex);
10808c2ecf20Sopenharmony_ci		}
10818c2ecf20Sopenharmony_ci		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
10828c2ecf20Sopenharmony_ci			sl->ttl = dev->slave_ttl;
10838c2ecf20Sopenharmony_ci	}
10848c2ecf20Sopenharmony_ci	mutex_unlock(&dev->list_mutex);
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci	if (dev->search_count > 0)
10878c2ecf20Sopenharmony_ci		dev->search_count--;
10888c2ecf20Sopenharmony_ci}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistatic void w1_search_process(struct w1_master *dev, u8 search_type)
10918c2ecf20Sopenharmony_ci{
10928c2ecf20Sopenharmony_ci	w1_search_process_cb(dev, search_type, w1_slave_found);
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci/**
10968c2ecf20Sopenharmony_ci * w1_process_callbacks() - execute each dev->async_list callback entry
10978c2ecf20Sopenharmony_ci * @dev: w1_master device
10988c2ecf20Sopenharmony_ci *
10998c2ecf20Sopenharmony_ci * The w1 master list_mutex must be held.
11008c2ecf20Sopenharmony_ci *
11018c2ecf20Sopenharmony_ci * Return: 1 if there were commands to executed 0 otherwise
11028c2ecf20Sopenharmony_ci */
11038c2ecf20Sopenharmony_ciint w1_process_callbacks(struct w1_master *dev)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	int ret = 0;
11068c2ecf20Sopenharmony_ci	struct w1_async_cmd *async_cmd, *async_n;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	/* The list can be added to in another thread, loop until it is empty */
11098c2ecf20Sopenharmony_ci	while (!list_empty(&dev->async_list)) {
11108c2ecf20Sopenharmony_ci		list_for_each_entry_safe(async_cmd, async_n, &dev->async_list,
11118c2ecf20Sopenharmony_ci			async_entry) {
11128c2ecf20Sopenharmony_ci			/* drop the lock, if it is a search it can take a long
11138c2ecf20Sopenharmony_ci			 * time */
11148c2ecf20Sopenharmony_ci			mutex_unlock(&dev->list_mutex);
11158c2ecf20Sopenharmony_ci			async_cmd->cb(dev, async_cmd);
11168c2ecf20Sopenharmony_ci			ret = 1;
11178c2ecf20Sopenharmony_ci			mutex_lock(&dev->list_mutex);
11188c2ecf20Sopenharmony_ci		}
11198c2ecf20Sopenharmony_ci	}
11208c2ecf20Sopenharmony_ci	return ret;
11218c2ecf20Sopenharmony_ci}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ciint w1_process(void *data)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	struct w1_master *dev = (struct w1_master *) data;
11268c2ecf20Sopenharmony_ci	/* As long as w1_timeout is only set by a module parameter the sleep
11278c2ecf20Sopenharmony_ci	 * time can be calculated in jiffies once.
11288c2ecf20Sopenharmony_ci	 */
11298c2ecf20Sopenharmony_ci	const unsigned long jtime =
11308c2ecf20Sopenharmony_ci	  usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us);
11318c2ecf20Sopenharmony_ci	/* remainder if it woke up early */
11328c2ecf20Sopenharmony_ci	unsigned long jremain = 0;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	atomic_inc(&dev->refcnt);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	for (;;) {
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		if (!jremain && dev->search_count) {
11398c2ecf20Sopenharmony_ci			mutex_lock(&dev->mutex);
11408c2ecf20Sopenharmony_ci			w1_search_process(dev, W1_SEARCH);
11418c2ecf20Sopenharmony_ci			mutex_unlock(&dev->mutex);
11428c2ecf20Sopenharmony_ci		}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		mutex_lock(&dev->list_mutex);
11458c2ecf20Sopenharmony_ci		/* Note, w1_process_callback drops the lock while processing,
11468c2ecf20Sopenharmony_ci		 * but locks it again before returning.
11478c2ecf20Sopenharmony_ci		 */
11488c2ecf20Sopenharmony_ci		if (!w1_process_callbacks(dev) && jremain) {
11498c2ecf20Sopenharmony_ci			/* a wake up is either to stop the thread, process
11508c2ecf20Sopenharmony_ci			 * callbacks, or search, it isn't process callbacks, so
11518c2ecf20Sopenharmony_ci			 * schedule a search.
11528c2ecf20Sopenharmony_ci			 */
11538c2ecf20Sopenharmony_ci			jremain = 1;
11548c2ecf20Sopenharmony_ci		}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci		__set_current_state(TASK_INTERRUPTIBLE);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci		/* hold list_mutex until after interruptible to prevent loosing
11598c2ecf20Sopenharmony_ci		 * the wakeup signal when async_cmd is added.
11608c2ecf20Sopenharmony_ci		 */
11618c2ecf20Sopenharmony_ci		mutex_unlock(&dev->list_mutex);
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_ci		if (kthread_should_stop()) {
11648c2ecf20Sopenharmony_ci			__set_current_state(TASK_RUNNING);
11658c2ecf20Sopenharmony_ci			break;
11668c2ecf20Sopenharmony_ci		}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci		/* Only sleep when the search is active. */
11698c2ecf20Sopenharmony_ci		if (dev->search_count) {
11708c2ecf20Sopenharmony_ci			if (!jremain)
11718c2ecf20Sopenharmony_ci				jremain = jtime;
11728c2ecf20Sopenharmony_ci			jremain = schedule_timeout(jremain);
11738c2ecf20Sopenharmony_ci		}
11748c2ecf20Sopenharmony_ci		else
11758c2ecf20Sopenharmony_ci			schedule();
11768c2ecf20Sopenharmony_ci	}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci	atomic_dec(&dev->refcnt);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	return 0;
11818c2ecf20Sopenharmony_ci}
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_cistatic int __init w1_init(void)
11848c2ecf20Sopenharmony_ci{
11858c2ecf20Sopenharmony_ci	int retval;
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	pr_info("Driver for 1-wire Dallas network protocol.\n");
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	w1_init_netlink();
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci	retval = bus_register(&w1_bus_type);
11928c2ecf20Sopenharmony_ci	if (retval) {
11938c2ecf20Sopenharmony_ci		pr_err("Failed to register bus. err=%d.\n", retval);
11948c2ecf20Sopenharmony_ci		goto err_out_exit_init;
11958c2ecf20Sopenharmony_ci	}
11968c2ecf20Sopenharmony_ci
11978c2ecf20Sopenharmony_ci	retval = driver_register(&w1_master_driver);
11988c2ecf20Sopenharmony_ci	if (retval) {
11998c2ecf20Sopenharmony_ci		pr_err("Failed to register master driver. err=%d.\n",
12008c2ecf20Sopenharmony_ci			retval);
12018c2ecf20Sopenharmony_ci		goto err_out_bus_unregister;
12028c2ecf20Sopenharmony_ci	}
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	retval = driver_register(&w1_slave_driver);
12058c2ecf20Sopenharmony_ci	if (retval) {
12068c2ecf20Sopenharmony_ci		pr_err("Failed to register slave driver. err=%d.\n",
12078c2ecf20Sopenharmony_ci			retval);
12088c2ecf20Sopenharmony_ci		goto err_out_master_unregister;
12098c2ecf20Sopenharmony_ci	}
12108c2ecf20Sopenharmony_ci
12118c2ecf20Sopenharmony_ci	return 0;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci#if 0
12148c2ecf20Sopenharmony_ci/* For undoing the slave register if there was a step after it. */
12158c2ecf20Sopenharmony_cierr_out_slave_unregister:
12168c2ecf20Sopenharmony_ci	driver_unregister(&w1_slave_driver);
12178c2ecf20Sopenharmony_ci#endif
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_cierr_out_master_unregister:
12208c2ecf20Sopenharmony_ci	driver_unregister(&w1_master_driver);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_cierr_out_bus_unregister:
12238c2ecf20Sopenharmony_ci	bus_unregister(&w1_bus_type);
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_cierr_out_exit_init:
12268c2ecf20Sopenharmony_ci	return retval;
12278c2ecf20Sopenharmony_ci}
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_cistatic void __exit w1_fini(void)
12308c2ecf20Sopenharmony_ci{
12318c2ecf20Sopenharmony_ci	struct w1_master *dev, *n;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci	/* Set netlink removal messages and some cleanup */
12348c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry)
12358c2ecf20Sopenharmony_ci		__w1_remove_master_device(dev);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	w1_fini_netlink();
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	driver_unregister(&w1_slave_driver);
12408c2ecf20Sopenharmony_ci	driver_unregister(&w1_master_driver);
12418c2ecf20Sopenharmony_ci	bus_unregister(&w1_bus_type);
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_cimodule_init(w1_init);
12458c2ecf20Sopenharmony_cimodule_exit(w1_fini);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ciMODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
12488c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
12498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1250