xref: /openbmc/linux/drivers/w1/w1.c (revision d0034a7a4ac7fae708146ac0059b9c47a1543f0d)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
3a8018766SEvgeniy Polyakov  * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
41da177e4SLinus Torvalds  */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <linux/delay.h>
71da177e4SLinus Torvalds #include <linux/kernel.h>
81da177e4SLinus Torvalds #include <linux/module.h>
91da177e4SLinus Torvalds #include <linux/moduleparam.h>
101da177e4SLinus Torvalds #include <linux/list.h>
111da177e4SLinus Torvalds #include <linux/interrupt.h>
121da177e4SLinus Torvalds #include <linux/spinlock.h>
131da177e4SLinus Torvalds #include <linux/timer.h>
141da177e4SLinus Torvalds #include <linux/device.h>
151da177e4SLinus Torvalds #include <linux/slab.h>
161da177e4SLinus Torvalds #include <linux/sched.h>
17674a396cSEvgeniy Polyakov #include <linux/kthread.h>
187dfb7103SNigel Cunningham #include <linux/freezer.h>
192eb79548SJaghathiswari Rankappagounder Natarajan #include <linux/hwmon.h>
20fae68031SDaniel Mack #include <linux/of.h>
211da177e4SLinus Torvalds 
2260063497SArun Sharma #include <linux/atomic.h>
231da177e4SLinus Torvalds 
24de0d6dbdSAndrew F. Davis #include "w1_internal.h"
251da177e4SLinus Torvalds #include "w1_netlink.h"
261da177e4SLinus Torvalds 
27de0d6dbdSAndrew F. Davis #define W1_FAMILY_DEFAULT	0
28*48b7de66SChristian Vogel #define W1_FAMILY_DS28E04       0x1C /* for crc quirk */
29*48b7de66SChristian Vogel 
30de0d6dbdSAndrew F. Davis 
311da177e4SLinus Torvalds static int w1_timeout = 10;
321da177e4SLinus Torvalds module_param_named(timeout, w1_timeout, int, 0);
33b3be177aSDavid Fries MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
3450fa2951SAndrew F. Davis 
3550fa2951SAndrew F. Davis static int w1_timeout_us;
36c3098356SDmitry Khromov module_param_named(timeout_us, w1_timeout_us, int, 0);
37a46b195cSWei Yongjun MODULE_PARM_DESC(timeout_us,
38a46b195cSWei Yongjun 		 "time in microseconds between automatic slave searches");
3950fa2951SAndrew F. Davis 
40b3be177aSDavid Fries /* A search stops when w1_max_slave_count devices have been found in that
41b3be177aSDavid Fries  * search.  The next search will start over and detect the same set of devices
42b3be177aSDavid Fries  * on a static 1-wire bus.  Memory is not allocated based on this number, just
43b3be177aSDavid Fries  * on the number of devices known to the kernel.  Having a high number does not
44b3be177aSDavid Fries  * consume additional resources.  As a special case, if there is only one
45b3be177aSDavid Fries  * device on the network and w1_max_slave_count is set to 1, the device id can
46b3be177aSDavid Fries  * be read directly skipping the normal slower search process.
47b3be177aSDavid Fries  */
4850fa2951SAndrew F. Davis int w1_max_slave_count = 64;
491da177e4SLinus Torvalds module_param_named(max_slave_count, w1_max_slave_count, int, 0);
50b3be177aSDavid Fries MODULE_PARM_DESC(max_slave_count,
51b3be177aSDavid Fries 	"maximum number of slaves detected in a search");
5250fa2951SAndrew F. Davis 
5350fa2951SAndrew F. Davis int w1_max_slave_ttl = 10;
541da177e4SLinus Torvalds module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
55b3be177aSDavid Fries MODULE_PARM_DESC(slave_ttl,
56b3be177aSDavid Fries 	"Number of searches not seeing a slave before it will be removed");
571da177e4SLinus Torvalds 
58abd52a13SEvgeniy Polyakov DEFINE_MUTEX(w1_mlock);
591da177e4SLinus Torvalds LIST_HEAD(w1_masters);
601da177e4SLinus Torvalds 
w1_master_probe(struct device * dev)611da177e4SLinus Torvalds static int w1_master_probe(struct device *dev)
621da177e4SLinus Torvalds {
631da177e4SLinus Torvalds 	return -ENODEV;
641da177e4SLinus Torvalds }
651da177e4SLinus Torvalds 
w1_master_release(struct device * dev)661da177e4SLinus Torvalds static void w1_master_release(struct device *dev)
671da177e4SLinus Torvalds {
681da177e4SLinus Torvalds 	struct w1_master *md = dev_to_w1_master(dev);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	dev_dbg(dev, "%s: Releasing %s.\n", __func__, md->name);
711da177e4SLinus Torvalds 	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
721da177e4SLinus Torvalds 	kfree(md);
73db2d0008SEvgeniy Polyakov }
743aca692dSEvgeniy Polyakov 
w1_slave_release(struct device * dev)753aca692dSEvgeniy Polyakov static void w1_slave_release(struct device *dev)
763aca692dSEvgeniy Polyakov {
773aca692dSEvgeniy Polyakov 	struct w1_slave *sl = dev_to_w1_slave(dev);
781da177e4SLinus Torvalds 
791da177e4SLinus Torvalds 	dev_dbg(dev, "%s: Releasing %s [%p]\n", __func__, sl->name, sl);
801da177e4SLinus Torvalds 
811da177e4SLinus Torvalds 	w1_family_put(sl->family);
82db2d0008SEvgeniy Polyakov 	sl->master->slave_count--;
833aca692dSEvgeniy Polyakov }
849fcbbac5SDavid Fries 
name_show(struct device * dev,struct device_attribute * attr,char * buf)853aca692dSEvgeniy Polyakov static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
863aca692dSEvgeniy Polyakov {
873aca692dSEvgeniy Polyakov 	struct w1_slave *sl = dev_to_w1_slave(dev);
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	return sprintf(buf, "%s\n", sl->name);
905b187b3cSGreg Kroah-Hartman }
911da177e4SLinus Torvalds static DEVICE_ATTR_RO(name);
92d2a4ef6aSEvgeniy Polyakov 
id_show(struct device * dev,struct device_attribute * attr,char * buf)93d2a4ef6aSEvgeniy Polyakov static ssize_t id_show(struct device *dev,
94d2a4ef6aSEvgeniy Polyakov 	struct device_attribute *attr, char *buf)
951da177e4SLinus Torvalds {
965b187b3cSGreg Kroah-Hartman 	struct w1_slave *sl = dev_to_w1_slave(dev);
971da177e4SLinus Torvalds 	ssize_t count = sizeof(sl->reg_num);
985b187b3cSGreg Kroah-Hartman 
9907e00341SDavid Fries 	memcpy(buf, (u8 *)&sl->reg_num, count);
1001da177e4SLinus Torvalds 	return count;
10107e00341SDavid Fries }
10207e00341SDavid Fries static DEVICE_ATTR_RO(id);
103d2a4ef6aSEvgeniy Polyakov 
104d2a4ef6aSEvgeniy Polyakov static struct attribute *w1_slave_attrs[] = {
105d2a4ef6aSEvgeniy Polyakov 	&dev_attr_name.attr,
1061da177e4SLinus Torvalds 	&dev_attr_id.attr,
1075b187b3cSGreg Kroah-Hartman 	NULL,
1081da177e4SLinus Torvalds };
1095b187b3cSGreg Kroah-Hartman ATTRIBUTE_GROUPS(w1_slave);
1105b187b3cSGreg Kroah-Hartman 
1115b187b3cSGreg Kroah-Hartman /* Default family */
1125b187b3cSGreg Kroah-Hartman 
rw_write(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)1135b187b3cSGreg Kroah-Hartman static ssize_t rw_write(struct file *filp, struct kobject *kobj,
1145b187b3cSGreg Kroah-Hartman 			struct bin_attribute *bin_attr, char *buf, loff_t off,
1157785925dSEvgeniy Polyakov 			size_t count)
116d2a4ef6aSEvgeniy Polyakov {
117f522d239SEvgeniy Polyakov 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
11836c27a65SGreg Kroah-Hartman 
11936c27a65SGreg Kroah-Hartman 	mutex_lock(&sl->master->mutex);
12036c27a65SGreg Kroah-Hartman 	if (w1_reset_select_slave(sl)) {
121f522d239SEvgeniy Polyakov 		count = 0;
122f522d239SEvgeniy Polyakov 		goto out_up;
123f522d239SEvgeniy Polyakov 	}
124abd52a13SEvgeniy Polyakov 
125f522d239SEvgeniy Polyakov 	w1_write_block(sl->master, buf, count);
126f522d239SEvgeniy Polyakov 
127f522d239SEvgeniy Polyakov out_up:
128f522d239SEvgeniy Polyakov 	mutex_unlock(&sl->master->mutex);
129f522d239SEvgeniy Polyakov 	return count;
130f522d239SEvgeniy Polyakov }
131f522d239SEvgeniy Polyakov 
rw_read(struct file * filp,struct kobject * kobj,struct bin_attribute * bin_attr,char * buf,loff_t off,size_t count)132f522d239SEvgeniy Polyakov static ssize_t rw_read(struct file *filp, struct kobject *kobj,
133abd52a13SEvgeniy Polyakov 		       struct bin_attribute *bin_attr, char *buf, loff_t off,
134f522d239SEvgeniy Polyakov 		       size_t count)
135f522d239SEvgeniy Polyakov {
136f522d239SEvgeniy Polyakov 	struct w1_slave *sl = kobj_to_w1_slave(kobj);
13736c27a65SGreg Kroah-Hartman 
13836c27a65SGreg Kroah-Hartman 	mutex_lock(&sl->master->mutex);
13936c27a65SGreg Kroah-Hartman 	w1_read_block(sl->master, buf, count);
140f522d239SEvgeniy Polyakov 	mutex_unlock(&sl->master->mutex);
141f522d239SEvgeniy Polyakov 	return count;
142f522d239SEvgeniy Polyakov }
143abd52a13SEvgeniy Polyakov 
144f522d239SEvgeniy Polyakov static BIN_ATTR_RW(rw, PAGE_SIZE);
145abd52a13SEvgeniy Polyakov 
146f522d239SEvgeniy Polyakov static struct bin_attribute *w1_slave_bin_attrs[] = {
147f522d239SEvgeniy Polyakov 	&bin_attr_rw,
148f522d239SEvgeniy Polyakov 	NULL,
14936c27a65SGreg Kroah-Hartman };
15036c27a65SGreg Kroah-Hartman 
15136c27a65SGreg Kroah-Hartman static const struct attribute_group w1_slave_default_group = {
15236c27a65SGreg Kroah-Hartman 	.bin_attrs = w1_slave_bin_attrs,
15336c27a65SGreg Kroah-Hartman };
154f522d239SEvgeniy Polyakov 
155f522d239SEvgeniy Polyakov static const struct attribute_group *w1_slave_default_groups[] = {
15636c27a65SGreg Kroah-Hartman 	&w1_slave_default_group,
15736c27a65SGreg Kroah-Hartman 	NULL,
15836c27a65SGreg Kroah-Hartman };
159f522d239SEvgeniy Polyakov 
16036c27a65SGreg Kroah-Hartman static const struct w1_family_ops w1_default_fops = {
16136c27a65SGreg Kroah-Hartman 	.groups		= w1_slave_default_groups,
16236c27a65SGreg Kroah-Hartman };
16336c27a65SGreg Kroah-Hartman 
164f522d239SEvgeniy Polyakov static struct w1_family w1_default_family = {
16557de2dfcSRikard Falkeborn 	.fops = &w1_default_fops,
16636c27a65SGreg Kroah-Hartman };
167f522d239SEvgeniy Polyakov 
168f522d239SEvgeniy Polyakov static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env);
169f522d239SEvgeniy Polyakov 
170f522d239SEvgeniy Polyakov static struct bus_type w1_bus_type = {
171f522d239SEvgeniy Polyakov 	.name = "w1",
172d2a4ef6aSEvgeniy Polyakov 	.uevent = w1_uevent,
1737eff2e7aSKay Sievers };
1747785925dSEvgeniy Polyakov 
1751da177e4SLinus Torvalds struct device_driver w1_master_driver = {
1761da177e4SLinus Torvalds 	.name = "w1_master_driver",
1771da177e4SLinus Torvalds 	.bus = &w1_bus_type,
178312c004dSKay Sievers 	.probe = w1_master_probe,
1791da177e4SLinus Torvalds };
1801da177e4SLinus Torvalds 
1817f772ed8SEvgeniy Polyakov struct device w1_master_device = {
1827f772ed8SEvgeniy Polyakov 	.parent = NULL,
1831da177e4SLinus Torvalds 	.bus = &w1_bus_type,
1841da177e4SLinus Torvalds 	.init_name = "w1 bus master",
1851da177e4SLinus Torvalds 	.driver = &w1_master_driver,
1861da177e4SLinus Torvalds 	.release = &w1_master_release
1877f772ed8SEvgeniy Polyakov };
1881da177e4SLinus Torvalds 
1891da177e4SLinus Torvalds static struct device_driver w1_slave_driver = {
19040f91de6SKay Sievers 	.name = "w1_slave_driver",
1917f772ed8SEvgeniy Polyakov 	.bus = &w1_bus_type,
1921da177e4SLinus Torvalds };
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds #if 0
1952c5bfdacSEvgeniy Polyakov struct device w1_slave_device = {
1967f772ed8SEvgeniy Polyakov 	.parent = NULL,
1977f772ed8SEvgeniy Polyakov 	.bus = &w1_bus_type,
1987f772ed8SEvgeniy Polyakov 	.init_name = "w1 bus slave",
1997f772ed8SEvgeniy Polyakov 	.driver = &w1_slave_driver,
2002c5bfdacSEvgeniy Polyakov 	.release = &w1_slave_release
2017f772ed8SEvgeniy Polyakov };
2027f772ed8SEvgeniy Polyakov #endif  /*  0  */
2037f772ed8SEvgeniy Polyakov 
w1_master_attribute_show_name(struct device * dev,struct device_attribute * attr,char * buf)20440f91de6SKay Sievers static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
2057f772ed8SEvgeniy Polyakov {
2063aca692dSEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2077f772ed8SEvgeniy Polyakov 	ssize_t count;
2082c5bfdacSEvgeniy Polyakov 
2097f772ed8SEvgeniy Polyakov 	mutex_lock(&md->mutex);
210060b8845SYani Ioannou 	count = sprintf(buf, "%s\n", md->name);
2111da177e4SLinus Torvalds 	mutex_unlock(&md->mutex);
212db2d0008SEvgeniy Polyakov 
2131da177e4SLinus Torvalds 	return count;
2141da177e4SLinus Torvalds }
215abd52a13SEvgeniy Polyakov 
w1_master_attribute_store_search(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2161da177e4SLinus Torvalds static ssize_t w1_master_attribute_store_search(struct device * dev,
217abd52a13SEvgeniy Polyakov 						struct device_attribute *attr,
2181da177e4SLinus Torvalds 						const char * buf, size_t count)
2191da177e4SLinus Torvalds {
2201da177e4SLinus Torvalds 	long tmp;
2211da177e4SLinus Torvalds 	struct w1_master *md = dev_to_w1_master(dev);
2222a9d0c17SEvgeniy Polyakov 	int ret;
2232a9d0c17SEvgeniy Polyakov 
2242a9d0c17SEvgeniy Polyakov 	ret = kstrtol(buf, 0, &tmp);
2252a9d0c17SEvgeniy Polyakov 	if (ret)
2266a158c0dSDavid Fries 		return ret;
227db2d0008SEvgeniy Polyakov 
228bf4228f0SJingoo Han 	mutex_lock(&md->mutex);
2292a9d0c17SEvgeniy Polyakov 	md->search_count = tmp;
230bf4228f0SJingoo Han 	mutex_unlock(&md->mutex);
231bf4228f0SJingoo Han 	/* Only wake if it is going to be searching. */
232bf4228f0SJingoo Han 	if (tmp)
2336a158c0dSDavid Fries 		wake_up_process(md->thread);
234abd52a13SEvgeniy Polyakov 
2356a158c0dSDavid Fries 	return count;
236abd52a13SEvgeniy Polyakov }
237af8c7237SDavid Fries 
w1_master_attribute_show_search(struct device * dev,struct device_attribute * attr,char * buf)238af8c7237SDavid Fries static ssize_t w1_master_attribute_show_search(struct device *dev,
2393c52e4e6SDavid Fries 					       struct device_attribute *attr,
2402a9d0c17SEvgeniy Polyakov 					       char *buf)
2412a9d0c17SEvgeniy Polyakov {
2422a9d0c17SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2432a9d0c17SEvgeniy Polyakov 	ssize_t count;
2442a9d0c17SEvgeniy Polyakov 
2452a9d0c17SEvgeniy Polyakov 	mutex_lock(&md->mutex);
2462a9d0c17SEvgeniy Polyakov 	count = sprintf(buf, "%d\n", md->search_count);
2472a9d0c17SEvgeniy Polyakov 	mutex_unlock(&md->mutex);
248db2d0008SEvgeniy Polyakov 
2492a9d0c17SEvgeniy Polyakov 	return count;
2502a9d0c17SEvgeniy Polyakov }
251abd52a13SEvgeniy Polyakov 
w1_master_attribute_store_pullup(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)2522a9d0c17SEvgeniy Polyakov static ssize_t w1_master_attribute_store_pullup(struct device *dev,
253abd52a13SEvgeniy Polyakov 						struct device_attribute *attr,
2542a9d0c17SEvgeniy Polyakov 						const char *buf, size_t count)
2552a9d0c17SEvgeniy Polyakov {
2562a9d0c17SEvgeniy Polyakov 	long tmp;
2572a9d0c17SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2586a158c0dSDavid Fries 	int ret;
2596a158c0dSDavid Fries 
2606a158c0dSDavid Fries 	ret = kstrtol(buf, 0, &tmp);
2616a158c0dSDavid Fries 	if (ret)
2626a158c0dSDavid Fries 		return ret;
2636a158c0dSDavid Fries 
264bf4228f0SJingoo Han 	mutex_lock(&md->mutex);
2656a158c0dSDavid Fries 	md->enable_pullup = tmp;
266bf4228f0SJingoo Han 	mutex_unlock(&md->mutex);
267bf4228f0SJingoo Han 
268bf4228f0SJingoo Han 	return count;
2696a158c0dSDavid Fries }
2706a158c0dSDavid Fries 
w1_master_attribute_show_pullup(struct device * dev,struct device_attribute * attr,char * buf)2716a158c0dSDavid Fries static ssize_t w1_master_attribute_show_pullup(struct device *dev,
2726a158c0dSDavid Fries 					       struct device_attribute *attr,
2736a158c0dSDavid Fries 					       char *buf)
2746a158c0dSDavid Fries {
2756a158c0dSDavid Fries 	struct w1_master *md = dev_to_w1_master(dev);
2766a158c0dSDavid Fries 	ssize_t count;
2776a158c0dSDavid Fries 
2786a158c0dSDavid Fries 	mutex_lock(&md->mutex);
2796a158c0dSDavid Fries 	count = sprintf(buf, "%d\n", md->enable_pullup);
2806a158c0dSDavid Fries 	mutex_unlock(&md->mutex);
2816a158c0dSDavid Fries 
2826a158c0dSDavid Fries 	return count;
2836a158c0dSDavid Fries }
2846a158c0dSDavid Fries 
w1_master_attribute_show_pointer(struct device * dev,struct device_attribute * attr,char * buf)2856a158c0dSDavid Fries static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
2866a158c0dSDavid Fries {
2876a158c0dSDavid Fries 	struct w1_master *md = dev_to_w1_master(dev);
2886a158c0dSDavid Fries 	ssize_t count;
2896a158c0dSDavid Fries 
2906a158c0dSDavid Fries 	mutex_lock(&md->mutex);
291060b8845SYani Ioannou 	count = sprintf(buf, "0x%p\n", md->bus_master);
2921da177e4SLinus Torvalds 	mutex_unlock(&md->mutex);
293db2d0008SEvgeniy Polyakov 	return count;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds 
w1_master_attribute_show_timeout(struct device * dev,struct device_attribute * attr,char * buf)296abd52a13SEvgeniy Polyakov static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
2971da177e4SLinus Torvalds {
298abd52a13SEvgeniy Polyakov 	return sprintf(buf, "%d\n", w1_timeout);
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds 
w1_master_attribute_show_timeout_us(struct device * dev,struct device_attribute * attr,char * buf)3011da177e4SLinus Torvalds static ssize_t w1_master_attribute_show_timeout_us(struct device *dev,
302060b8845SYani Ioannou 	struct device_attribute *attr, char *buf)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds 	return sprintf(buf, "%d\n", w1_timeout_us);
3051da177e4SLinus Torvalds }
3061da177e4SLinus Torvalds 
w1_master_attribute_store_max_slave_count(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)3071da177e4SLinus Torvalds static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
3081da177e4SLinus Torvalds 	struct device_attribute *attr, const char *buf, size_t count)
309c3098356SDmitry Khromov {
310c3098356SDmitry Khromov 	int tmp;
311c3098356SDmitry Khromov 	struct w1_master *md = dev_to_w1_master(dev);
312c3098356SDmitry Khromov 
313c3098356SDmitry Khromov 	if (kstrtoint(buf, 0, &tmp) || tmp < 1)
314c3098356SDmitry Khromov 		return -EINVAL;
315c3098356SDmitry Khromov 
316c3098356SDmitry Khromov 	mutex_lock(&md->mutex);
317a1613056SDavid Fries 	md->max_slave_count = tmp;
318a1613056SDavid Fries 	/* allow each time the max_slave_count is updated */
319a1613056SDavid Fries 	clear_bit(W1_WARN_MAX_COUNT, &md->flags);
320a7155f4eSDan Carpenter 	mutex_unlock(&md->mutex);
321a1613056SDavid Fries 
322a1613056SDavid Fries 	return count;
323b9c11a23SDan Carpenter }
324a1613056SDavid Fries 
w1_master_attribute_show_max_slave_count(struct device * dev,struct device_attribute * attr,char * buf)325a1613056SDavid Fries static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
326a1613056SDavid Fries {
327a1613056SDavid Fries 	struct w1_master *md = dev_to_w1_master(dev);
328a1613056SDavid Fries 	ssize_t count;
329a1613056SDavid Fries 
330a1613056SDavid Fries 	mutex_lock(&md->mutex);
331a1613056SDavid Fries 	count = sprintf(buf, "%d\n", md->max_slave_count);
332a1613056SDavid Fries 	mutex_unlock(&md->mutex);
333a1613056SDavid Fries 	return count;
334a1613056SDavid Fries }
335060b8845SYani Ioannou 
w1_master_attribute_show_attempts(struct device * dev,struct device_attribute * attr,char * buf)3361da177e4SLinus Torvalds static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
337db2d0008SEvgeniy Polyakov {
3381da177e4SLinus Torvalds 	struct w1_master *md = dev_to_w1_master(dev);
3391da177e4SLinus Torvalds 	ssize_t count;
340abd52a13SEvgeniy Polyakov 
3411da177e4SLinus Torvalds 	mutex_lock(&md->mutex);
342abd52a13SEvgeniy Polyakov 	count = sprintf(buf, "%lu\n", md->attempts);
3431da177e4SLinus Torvalds 	mutex_unlock(&md->mutex);
3441da177e4SLinus Torvalds 	return count;
3451da177e4SLinus Torvalds }
346060b8845SYani Ioannou 
w1_master_attribute_show_slave_count(struct device * dev,struct device_attribute * attr,char * buf)3471da177e4SLinus Torvalds static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
348db2d0008SEvgeniy Polyakov {
3491da177e4SLinus Torvalds 	struct w1_master *md = dev_to_w1_master(dev);
3501da177e4SLinus Torvalds 	ssize_t count;
351abd52a13SEvgeniy Polyakov 
3521da177e4SLinus Torvalds 	mutex_lock(&md->mutex);
353abd52a13SEvgeniy Polyakov 	count = sprintf(buf, "%d\n", md->slave_count);
3541da177e4SLinus Torvalds 	mutex_unlock(&md->mutex);
3551da177e4SLinus Torvalds 	return count;
3561da177e4SLinus Torvalds }
357060b8845SYani Ioannou 
w1_master_attribute_show_slaves(struct device * dev,struct device_attribute * attr,char * buf)3581da177e4SLinus Torvalds static ssize_t w1_master_attribute_show_slaves(struct device *dev,
359db2d0008SEvgeniy Polyakov 	struct device_attribute *attr, char *buf)
3601da177e4SLinus Torvalds {
3611da177e4SLinus Torvalds 	struct w1_master *md = dev_to_w1_master(dev);
362abd52a13SEvgeniy Polyakov 	int c = PAGE_SIZE;
3631da177e4SLinus Torvalds 	struct list_head *ent, *n;
364abd52a13SEvgeniy Polyakov 	struct w1_slave *sl = NULL;
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds 	mutex_lock(&md->list_mutex);
3671da177e4SLinus Torvalds 
3689b467411SDavid Fries 	list_for_each_safe(ent, n, &md->slist) {
3699b467411SDavid Fries 		sl = list_entry(ent, struct w1_slave, w1_slave_entry);
3701da177e4SLinus Torvalds 
371db2d0008SEvgeniy Polyakov 		c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
3721da177e4SLinus Torvalds 	}
3731da177e4SLinus Torvalds 	if (!sl)
3749fcbbac5SDavid Fries 		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
3759fcbbac5SDavid Fries 
3769fcbbac5SDavid Fries 	mutex_unlock(&md->list_mutex);
3771da177e4SLinus Torvalds 
3781da177e4SLinus Torvalds 	return PAGE_SIZE - c;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds 
w1_master_attribute_show_add(struct device * dev,struct device_attribute * attr,char * buf)3811da177e4SLinus Torvalds static ssize_t w1_master_attribute_show_add(struct device *dev,
3821da177e4SLinus Torvalds 	struct device_attribute *attr, char *buf)
3839fcbbac5SDavid Fries {
3849fcbbac5SDavid Fries 	int c = PAGE_SIZE;
3851da177e4SLinus Torvalds 	c -= snprintf(buf+PAGE_SIZE - c, c,
3869fcbbac5SDavid Fries 		"write device id xx-xxxxxxxxxxxx to add slave\n");
3871da177e4SLinus Torvalds 	return PAGE_SIZE - c;
3881da177e4SLinus Torvalds }
3891da177e4SLinus Torvalds 
w1_atoreg_num(struct device * dev,const char * buf,size_t count,struct w1_reg_num * rn)3901da177e4SLinus Torvalds static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
3919b467411SDavid Fries 	struct w1_reg_num *rn)
3929b467411SDavid Fries {
3939b467411SDavid Fries 	unsigned int family;
3949b467411SDavid Fries 	unsigned long long id;
3959b467411SDavid Fries 	int i;
3969b467411SDavid Fries 	u64 rn64_le;
3979b467411SDavid Fries 
3989b467411SDavid Fries 	/* The CRC value isn't read from the user because the sysfs directory
3999b467411SDavid Fries 	 * doesn't include it and most messages from the bus search don't
4009b467411SDavid Fries 	 * print it either.  It would be unreasonable for the user to then
4019b467411SDavid Fries 	 * provide it.
4029b467411SDavid Fries 	 */
4039b467411SDavid Fries 	const char *error_msg = "bad slave string format, expecting "
4049b467411SDavid Fries 		"ff-dddddddddddd\n";
4059b467411SDavid Fries 
4069b467411SDavid Fries 	if (buf[2] != '-') {
4079b467411SDavid Fries 		dev_err(dev, "%s", error_msg);
4089b467411SDavid Fries 		return -EINVAL;
4099b467411SDavid Fries 	}
4109b467411SDavid Fries 	i = sscanf(buf, "%02x-%012llx", &family, &id);
4119b467411SDavid Fries 	if (i != 2) {
4129b467411SDavid Fries 		dev_err(dev, "%s", error_msg);
4139b467411SDavid Fries 		return -EINVAL;
4149b467411SDavid Fries 	}
4159b467411SDavid Fries 	rn->family = family;
4169b467411SDavid Fries 	rn->id = id;
4179b467411SDavid Fries 
4189b467411SDavid Fries 	rn64_le = cpu_to_le64(*(u64 *)rn);
4199b467411SDavid Fries 	rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
4209b467411SDavid Fries 
4219b467411SDavid Fries #if 0
4229b467411SDavid Fries 	dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
4239b467411SDavid Fries 		  rn->family, (unsigned long long)rn->id, rn->crc);
4249b467411SDavid Fries #endif
4259b467411SDavid Fries 
4269b467411SDavid Fries 	return 0;
4279b467411SDavid Fries }
4289b467411SDavid Fries 
4299b467411SDavid Fries /* Searches the slaves in the w1_master and returns a pointer or NULL.
4309b467411SDavid Fries  * Note: must not hold list_mutex
4319b467411SDavid Fries  */
w1_slave_search_device(struct w1_master * dev,struct w1_reg_num * rn)4329b467411SDavid Fries struct w1_slave *w1_slave_search_device(struct w1_master *dev,
4339b467411SDavid Fries 	struct w1_reg_num *rn)
4349b467411SDavid Fries {
4359b467411SDavid Fries 	struct w1_slave *sl;
4369b467411SDavid Fries 	mutex_lock(&dev->list_mutex);
4379b467411SDavid Fries 	list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
4389b467411SDavid Fries 		if (sl->reg_num.family == rn->family &&
4399b467411SDavid Fries 				sl->reg_num.id == rn->id &&
4409fcbbac5SDavid Fries 				sl->reg_num.crc == rn->crc) {
4419b467411SDavid Fries 			mutex_unlock(&dev->list_mutex);
44270b34d2eSDavid Fries 			return sl;
4439b467411SDavid Fries 		}
4449b467411SDavid Fries 	}
4459b467411SDavid Fries 	mutex_unlock(&dev->list_mutex);
4469fcbbac5SDavid Fries 	return NULL;
4479b467411SDavid Fries }
4489b467411SDavid Fries 
w1_master_attribute_store_add(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4499b467411SDavid Fries static ssize_t w1_master_attribute_store_add(struct device *dev,
4509b467411SDavid Fries 						struct device_attribute *attr,
4519fcbbac5SDavid Fries 						const char *buf, size_t count)
4529b467411SDavid Fries {
4539b467411SDavid Fries 	struct w1_master *md = dev_to_w1_master(dev);
4549b467411SDavid Fries 	struct w1_reg_num rn;
4559fcbbac5SDavid Fries 	struct w1_slave *sl;
4569b467411SDavid Fries 	ssize_t result = count;
4579b467411SDavid Fries 
4589b467411SDavid Fries 	if (w1_atoreg_num(dev, buf, count, &rn))
4599b467411SDavid Fries 		return -EINVAL;
4609b467411SDavid Fries 
4619b467411SDavid Fries 	mutex_lock(&md->mutex);
4629b467411SDavid Fries 	sl = w1_slave_search_device(md, &rn);
4639b467411SDavid Fries 	/* It would be nice to do a targeted search one the one-wire bus
4649b467411SDavid Fries 	 * for the new device to see if it is out there or not.  But the
4659b467411SDavid Fries 	 * current search doesn't support that.
4669b467411SDavid Fries 	 */
4679b467411SDavid Fries 	if (sl) {
4689b467411SDavid Fries 		dev_info(dev, "Device %s already exists\n", sl->name);
4699b467411SDavid Fries 		result = -EINVAL;
4709b467411SDavid Fries 	} else {
4719b467411SDavid Fries 		w1_attach_slave_device(md, &rn);
4729b467411SDavid Fries 	}
4739b467411SDavid Fries 	mutex_unlock(&md->mutex);
4749b467411SDavid Fries 
4759b467411SDavid Fries 	return result;
4769b467411SDavid Fries }
4779b467411SDavid Fries 
w1_master_attribute_show_remove(struct device * dev,struct device_attribute * attr,char * buf)4789b467411SDavid Fries static ssize_t w1_master_attribute_show_remove(struct device *dev,
4799b467411SDavid Fries 	struct device_attribute *attr, char *buf)
4809b467411SDavid Fries {
4819b467411SDavid Fries 	int c = PAGE_SIZE;
4829b467411SDavid Fries 	c -= snprintf(buf+PAGE_SIZE - c, c,
4839b467411SDavid Fries 		"write device id xx-xxxxxxxxxxxx to remove slave\n");
4849b467411SDavid Fries 	return PAGE_SIZE - c;
4859b467411SDavid Fries }
4869b467411SDavid Fries 
w1_master_attribute_store_remove(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)4879b467411SDavid Fries static ssize_t w1_master_attribute_store_remove(struct device *dev,
4889b467411SDavid Fries 						struct device_attribute *attr,
4899b467411SDavid Fries 						const char *buf, size_t count)
4909b467411SDavid Fries {
4919b467411SDavid Fries 	struct w1_master *md = dev_to_w1_master(dev);
4929b467411SDavid Fries 	struct w1_reg_num rn;
4939b467411SDavid Fries 	struct w1_slave *sl;
4949b467411SDavid Fries 	ssize_t result;
4959b467411SDavid Fries 
4969b467411SDavid Fries 	if (w1_atoreg_num(dev, buf, count, &rn))
4979b467411SDavid Fries 		return -EINVAL;
4989b467411SDavid Fries 
4999b467411SDavid Fries 	mutex_lock(&md->mutex);
5009b467411SDavid Fries 	sl = w1_slave_search_device(md, &rn);
5019b467411SDavid Fries 	if (sl) {
5029b467411SDavid Fries 		result = w1_slave_detach(sl);
5039b467411SDavid Fries 		/* refcnt 0 means it was detached in the call */
5049b467411SDavid Fries 		if (result == 0)
5059b467411SDavid Fries 			result = count;
5069b467411SDavid Fries 	} else {
5079b467411SDavid Fries 		dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
5089b467411SDavid Fries 			(unsigned long long)rn.id);
5099b467411SDavid Fries 		result = -EINVAL;
5109b467411SDavid Fries 	}
5119b467411SDavid Fries 	mutex_unlock(&md->mutex);
5129fcbbac5SDavid Fries 
5139fcbbac5SDavid Fries 	return result;
5149fcbbac5SDavid Fries }
5159fcbbac5SDavid Fries 
5169b467411SDavid Fries #define W1_MASTER_ATTR_RO(_name, _mode)				\
5179b467411SDavid Fries 	struct device_attribute w1_master_attribute_##_name =	\
5189b467411SDavid Fries 		__ATTR(w1_master_##_name, _mode,		\
5199b467411SDavid Fries 		       w1_master_attribute_show_##_name, NULL)
5209b467411SDavid Fries 
5219b467411SDavid Fries #define W1_MASTER_ATTR_RW(_name, _mode)				\
5229b467411SDavid Fries 	struct device_attribute w1_master_attribute_##_name =	\
5239b467411SDavid Fries 		__ATTR(w1_master_##_name, _mode,		\
5249b467411SDavid Fries 		       w1_master_attribute_show_##_name,	\
5259b467411SDavid Fries 		       w1_master_attribute_store_##_name)
5267785925dSEvgeniy Polyakov 
5277785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(name, S_IRUGO);
5287785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
5297785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
5307785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
5312a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
5322a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
5332a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO);
5342a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
5352a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP);
5362a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP);
5377785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP);
5387785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP);
5397785925dSEvgeniy Polyakov 
540a1613056SDavid Fries static struct attribute *w1_master_default_attrs[] = {
5417785925dSEvgeniy Polyakov 	&w1_master_attribute_name.attr,
5427785925dSEvgeniy Polyakov 	&w1_master_attribute_slaves.attr,
543c3098356SDmitry Khromov 	&w1_master_attribute_slave_count.attr,
5447785925dSEvgeniy Polyakov 	&w1_master_attribute_max_slave_count.attr,
54512aa4c64SBrian Swetland 	&w1_master_attribute_attempts.attr,
54612aa4c64SBrian Swetland 	&w1_master_attribute_timeout.attr,
54712aa4c64SBrian Swetland 	&w1_master_attribute_timeout_us.attr,
54812aa4c64SBrian Swetland 	&w1_master_attribute_pointer.attr,
5497785925dSEvgeniy Polyakov 	&w1_master_attribute_search.attr,
5507785925dSEvgeniy Polyakov 	&w1_master_attribute_pullup.attr,
5517785925dSEvgeniy Polyakov 	&w1_master_attribute_add.attr,
5527785925dSEvgeniy Polyakov 	&w1_master_attribute_remove.attr,
5537785925dSEvgeniy Polyakov 	NULL
5547785925dSEvgeniy Polyakov };
5557785925dSEvgeniy Polyakov 
5567785925dSEvgeniy Polyakov static const struct attribute_group w1_master_defattr_group = {
557c3098356SDmitry Khromov 	.attrs = w1_master_default_attrs,
5587785925dSEvgeniy Polyakov };
5592a9d0c17SEvgeniy Polyakov 
w1_create_master_attributes(struct w1_master * master)5606a158c0dSDavid Fries int w1_create_master_attributes(struct w1_master *master)
5619b467411SDavid Fries {
5629b467411SDavid Fries 	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
5637785925dSEvgeniy Polyakov }
5641da177e4SLinus Torvalds 
w1_destroy_master_attributes(struct w1_master * master)5651da177e4SLinus Torvalds void w1_destroy_master_attributes(struct w1_master *master)
566a890d56aSArvind Yadav {
5677785925dSEvgeniy Polyakov 	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
5681da177e4SLinus Torvalds }
5691da177e4SLinus Torvalds 
w1_uevent(const struct device * dev,struct kobj_uevent_env * env)5707785925dSEvgeniy Polyakov static int w1_uevent(const struct device *dev, struct kobj_uevent_env *env)
5717785925dSEvgeniy Polyakov {
5727785925dSEvgeniy Polyakov 	const struct w1_master *md = NULL;
5737785925dSEvgeniy Polyakov 	const struct w1_slave *sl = NULL;
5747785925dSEvgeniy Polyakov 	const char *event_owner, *name;
575c30c9b15SDavid Fries 	int err = 0;
5767785925dSEvgeniy Polyakov 
5777785925dSEvgeniy Polyakov 	if (dev->driver == &w1_master_driver) {
5787785925dSEvgeniy Polyakov 		md = container_of(dev, struct w1_master, dev);
5797785925dSEvgeniy Polyakov 		event_owner = "master";
5807eff2e7aSKay Sievers 		name = md->name;
5817f772ed8SEvgeniy Polyakov 	} else if (dev->driver == &w1_slave_driver) {
5827f772ed8SEvgeniy Polyakov 		sl = container_of(dev, struct w1_slave, dev);
5837f772ed8SEvgeniy Polyakov 		event_owner = "slave";
5847f772ed8SEvgeniy Polyakov 		name = sl->name;
585526be416SDevendra Naga 	} else {
5867f772ed8SEvgeniy Polyakov 		dev_dbg(dev, "Unknown event.\n");
5877f772ed8SEvgeniy Polyakov 		return -EINVAL;
5887f772ed8SEvgeniy Polyakov 	}
5897f772ed8SEvgeniy Polyakov 
5907f772ed8SEvgeniy Polyakov 	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n",
5917f772ed8SEvgeniy Polyakov 			event_owner, name, dev_name(dev));
5927f772ed8SEvgeniy Polyakov 
5937f772ed8SEvgeniy Polyakov 	if (dev->driver != &w1_slave_driver || !sl)
5947f772ed8SEvgeniy Polyakov 		goto end;
5957f772ed8SEvgeniy Polyakov 
596312c004dSKay Sievers 	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
5977f772ed8SEvgeniy Polyakov 	if (err)
5987f772ed8SEvgeniy Polyakov 		goto end;
5997f772ed8SEvgeniy Polyakov 
600c6976a4eSAndrew Morton 	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
60140f91de6SKay Sievers 			     (unsigned long long)sl->reg_num.id);
6027f772ed8SEvgeniy Polyakov end:
6037f772ed8SEvgeniy Polyakov 	return err;
604526be416SDevendra Naga }
6057f772ed8SEvgeniy Polyakov 
w1_family_notify(unsigned long action,struct w1_slave * sl)6067eff2e7aSKay Sievers static int w1_family_notify(unsigned long action, struct w1_slave *sl)
6077f772ed8SEvgeniy Polyakov {
608526be416SDevendra Naga 	const struct w1_family_ops *fops;
6097f772ed8SEvgeniy Polyakov 	int err;
6107eff2e7aSKay Sievers 
611c6976a4eSAndrew Morton 	fops = sl->family->fops;
612526be416SDevendra Naga 
6137f772ed8SEvgeniy Polyakov 	if (!fops)
614526be416SDevendra Naga 		return 0;
6157f772ed8SEvgeniy Polyakov 
61618d7f891SDavid Fries 	switch (action) {
61747eba33aSGreg Kroah-Hartman 	case BUS_NOTIFY_ADD_DEVICE:
61807f8569fSRikard Falkeborn 		/* if the family driver needs to initialize something... */
61947eba33aSGreg Kroah-Hartman 		if (fops->add_slave) {
62047eba33aSGreg Kroah-Hartman 			err = fops->add_slave(sl);
62136c27a65SGreg Kroah-Hartman 			if (err < 0) {
62247eba33aSGreg Kroah-Hartman 				dev_err(&sl->dev,
6232962aeceSHans-Frieder Vogt 					"add_slave() call failed. err=%d\n",
6242962aeceSHans-Frieder Vogt 					err);
6252962aeceSHans-Frieder Vogt 				return err;
62647eba33aSGreg Kroah-Hartman 			}
62747eba33aSGreg Kroah-Hartman 		}
62847eba33aSGreg Kroah-Hartman 		if (fops->groups) {
62936c27a65SGreg Kroah-Hartman 			err = sysfs_create_groups(&sl->dev.kobj, fops->groups);
63036c27a65SGreg Kroah-Hartman 			if (err) {
63136c27a65SGreg Kroah-Hartman 				dev_err(&sl->dev,
63247eba33aSGreg Kroah-Hartman 					"sysfs group creation failed. err=%d\n",
63336c27a65SGreg Kroah-Hartman 					err);
63436c27a65SGreg Kroah-Hartman 				return err;
63547eba33aSGreg Kroah-Hartman 			}
63647eba33aSGreg Kroah-Hartman 		}
63736c27a65SGreg Kroah-Hartman 		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info) {
63836c27a65SGreg Kroah-Hartman 			struct device *hwmon
63936c27a65SGreg Kroah-Hartman 				= hwmon_device_register_with_info(&sl->dev,
64036c27a65SGreg Kroah-Hartman 						"w1_slave_temp", sl,
64136c27a65SGreg Kroah-Hartman 						fops->chip_info,
64236c27a65SGreg Kroah-Hartman 						NULL);
64336c27a65SGreg Kroah-Hartman 			if (IS_ERR(hwmon)) {
64436c27a65SGreg Kroah-Hartman 				dev_warn(&sl->dev,
64536c27a65SGreg Kroah-Hartman 					 "could not create hwmon device\n");
64636c27a65SGreg Kroah-Hartman 			} else {
6472eb79548SJaghathiswari Rankappagounder Natarajan 				sl->hwmon = hwmon;
6482eb79548SJaghathiswari Rankappagounder Natarajan 			}
6492eb79548SJaghathiswari Rankappagounder Natarajan 		}
6502eb79548SJaghathiswari Rankappagounder Natarajan 		break;
6512eb79548SJaghathiswari Rankappagounder Natarajan 	case BUS_NOTIFY_DEL_DEVICE:
6522eb79548SJaghathiswari Rankappagounder Natarajan 		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info &&
6532eb79548SJaghathiswari Rankappagounder Natarajan 			    sl->hwmon)
6542eb79548SJaghathiswari Rankappagounder Natarajan 			hwmon_device_unregister(sl->hwmon);
6552eb79548SJaghathiswari Rankappagounder Natarajan 		if (fops->remove_slave)
6562eb79548SJaghathiswari Rankappagounder Natarajan 			sl->family->fops->remove_slave(sl);
6572eb79548SJaghathiswari Rankappagounder Natarajan 		if (fops->groups)
6582eb79548SJaghathiswari Rankappagounder Natarajan 			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
6592eb79548SJaghathiswari Rankappagounder Natarajan 		break;
66047eba33aSGreg Kroah-Hartman 	}
66147eba33aSGreg Kroah-Hartman 	return 0;
6622eb79548SJaghathiswari Rankappagounder Natarajan }
6632eb79548SJaghathiswari Rankappagounder Natarajan 
__w1_attach_slave_device(struct w1_slave * sl)6642eb79548SJaghathiswari Rankappagounder Natarajan static int __w1_attach_slave_device(struct w1_slave *sl)
66536c27a65SGreg Kroah-Hartman {
66647eba33aSGreg Kroah-Hartman 	int err;
66736c27a65SGreg Kroah-Hartman 
66836c27a65SGreg Kroah-Hartman 	sl->dev.parent = &sl->master->dev;
66947eba33aSGreg Kroah-Hartman 	sl->dev.driver = &w1_slave_driver;
67047eba33aSGreg Kroah-Hartman 	sl->dev.bus = &w1_bus_type;
67147eba33aSGreg Kroah-Hartman 	sl->dev.release = &w1_slave_release;
67247eba33aSGreg Kroah-Hartman 	sl->dev.groups = w1_slave_groups;
67347eba33aSGreg Kroah-Hartman 	sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node,
6741da177e4SLinus Torvalds 						sl->family->of_match_table);
6751da177e4SLinus Torvalds 
6761da177e4SLinus Torvalds 	dev_set_name(&sl->dev, "%02x-%012llx",
6771da177e4SLinus Torvalds 		 (unsigned int) sl->reg_num.family,
6781da177e4SLinus Torvalds 		 (unsigned long long) sl->reg_num.id);
6797f772ed8SEvgeniy Polyakov 	snprintf(&sl->name[0], sizeof(sl->name),
6801da177e4SLinus Torvalds 		 "%02x-%012llx",
6811da177e4SLinus Torvalds 		 (unsigned int) sl->reg_num.family,
6825b187b3cSGreg Kroah-Hartman 		 (unsigned long long) sl->reg_num.id);
683fae68031SDaniel Mack 
684fae68031SDaniel Mack 	dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__,
6851da177e4SLinus Torvalds 		dev_name(&sl->dev), sl);
68640f91de6SKay Sievers 
6871da177e4SLinus Torvalds 	/* suppress for w1_family_notify before sending KOBJ_ADD */
6881da177e4SLinus Torvalds 	dev_set_uevent_suppress(&sl->dev, true);
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	err = device_register(&sl->dev);
6911da177e4SLinus Torvalds 	if (err < 0) {
6921da177e4SLinus Torvalds 		dev_err(&sl->dev,
6931da177e4SLinus Torvalds 			"Device registration [%s] failed. err=%d\n",
694c6976a4eSAndrew Morton 			dev_name(&sl->dev), err);
69540f91de6SKay Sievers 		of_node_put(sl->dev.of_node);
6961da177e4SLinus Torvalds 		put_device(&sl->dev);
69718d7f891SDavid Fries 		return err;
69818d7f891SDavid Fries 	}
69918d7f891SDavid Fries 	w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);
7001da177e4SLinus Torvalds 
7011da177e4SLinus Torvalds 	dev_set_uevent_suppress(&sl->dev, false);
7021da177e4SLinus Torvalds 	kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
7031da177e4SLinus Torvalds 
70440f91de6SKay Sievers 	mutex_lock(&sl->master->list_mutex);
7050ec4eb71SArvind Yadav 	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
7061da177e4SLinus Torvalds 	mutex_unlock(&sl->master->list_mutex);
7071da177e4SLinus Torvalds 
70818d7f891SDavid Fries 	return 0;
7091da177e4SLinus Torvalds }
71047eba33aSGreg Kroah-Hartman 
w1_attach_slave_device(struct w1_master * dev,struct w1_reg_num * rn)71147eba33aSGreg Kroah-Hartman int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
7121da177e4SLinus Torvalds {
7139fcbbac5SDavid Fries 	struct w1_slave *sl;
7141da177e4SLinus Torvalds 	struct w1_family *f;
7159fcbbac5SDavid Fries 	int err;
7161da177e4SLinus Torvalds 	struct w1_netlink_msg msg;
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
7191da177e4SLinus Torvalds 	if (!sl) {
72070b34d2eSDavid Fries 		dev_err(&dev->dev,
7211da177e4SLinus Torvalds 			 "%s: failed to allocate new slave device.\n",
7221da177e4SLinus Torvalds 			 __func__);
7231da177e4SLinus Torvalds 		return -ENOMEM;
7241da177e4SLinus Torvalds 	}
7251da177e4SLinus Torvalds 
7261da177e4SLinus Torvalds 
727dd00cc48SYoann Padioleau 	sl->owner = THIS_MODULE;
7281da177e4SLinus Torvalds 	sl->master = dev;
7291da177e4SLinus Torvalds 	set_bit(W1_SLAVE_ACTIVE, &sl->flags);
7301da177e4SLinus Torvalds 
7311da177e4SLinus Torvalds 	memset(&msg, 0, sizeof(msg));
7321da177e4SLinus Torvalds 	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
7331da177e4SLinus Torvalds 	atomic_set(&sl->refcnt, 1);
7341da177e4SLinus Torvalds 	atomic_inc(&sl->master->refcnt);
7351da177e4SLinus Torvalds 	dev->slave_count++;
7361da177e4SLinus Torvalds 	dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x\n",
7371da177e4SLinus Torvalds 		  rn->family, (unsigned long long)rn->id, rn->crc);
738bb670937SMichal Nazarewicz 
7391da177e4SLinus Torvalds 	/* slave modules need to be loaded in a context with unlocked mutex */
74012003375SEvgeniy Polyakov 	mutex_unlock(&dev->mutex);
7411da177e4SLinus Torvalds 	request_module("w1-family-0x%02X", rn->family);
7429fcbbac5SDavid Fries 	mutex_lock(&dev->mutex);
7439fcbbac5SDavid Fries 
7442c927c0cSAlex A. Mihaylov 	spin_lock(&w1_flock);
745f6887531SAndrew Worsley 	f = w1_family_registered(rn->family);
746f6887531SAndrew Worsley 	if (!f) {
7471da177e4SLinus Torvalds 		f= &w1_default_family;
748bc04d76dSHans-Frieder Vogt 		dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
749bc04d76dSHans-Frieder Vogt 			  rn->family, rn->family,
750065c0956SIngo Flaschberger 			  (unsigned long long)rn->id, rn->crc);
751bc04d76dSHans-Frieder Vogt 	}
7528d7bda51SAlexander Stein 	__w1_family_get(f);
7531da177e4SLinus Torvalds 	spin_unlock(&w1_flock);
7541da177e4SLinus Torvalds 
7551da177e4SLinus Torvalds 	sl->family = f;
75699c5bfe9SEvgeniy Polyakov 
7571da177e4SLinus Torvalds 	err = __w1_attach_slave_device(sl);
7581da177e4SLinus Torvalds 	if (err < 0) {
7591da177e4SLinus Torvalds 		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
7601da177e4SLinus Torvalds 			 sl->name);
7611da177e4SLinus Torvalds 		dev->slave_count--;
7621da177e4SLinus Torvalds 		w1_family_put(sl->family);
7631da177e4SLinus Torvalds 		atomic_dec(&sl->master->refcnt);
7641da177e4SLinus Torvalds 		kfree(sl);
7651da177e4SLinus Torvalds 		return err;
7661da177e4SLinus Torvalds 	}
7671da177e4SLinus Torvalds 
7681da177e4SLinus Torvalds 	sl->ttl = dev->slave_ttl;
7691da177e4SLinus Torvalds 
7702c927c0cSAlex A. Mihaylov 	memcpy(msg.id.id, rn, sizeof(msg.id));
7711da177e4SLinus Torvalds 	msg.type = W1_SLAVE_ADD;
772d2ce4ea1SMaciej S. Szmigiero 	w1_netlink_send(dev, &msg);
7731da177e4SLinus Torvalds 
7741da177e4SLinus Torvalds 	return 0;
7751da177e4SLinus Torvalds }
7761da177e4SLinus Torvalds 
w1_unref_slave(struct w1_slave * sl)7771da177e4SLinus Torvalds int w1_unref_slave(struct w1_slave *sl)
7781da177e4SLinus Torvalds {
77912003375SEvgeniy Polyakov 	struct w1_master *dev = sl->master;
7801da177e4SLinus Torvalds 	int refcnt;
7811da177e4SLinus Torvalds 	mutex_lock(&dev->list_mutex);
7821da177e4SLinus Torvalds 	refcnt = atomic_sub_return(1, &sl->refcnt);
7831da177e4SLinus Torvalds 	if (refcnt == 0) {
7841da177e4SLinus Torvalds 		struct w1_netlink_msg msg;
7851da177e4SLinus Torvalds 
7869fcbbac5SDavid Fries 		dev_dbg(&sl->dev, "%s: detaching %s [%p].\n", __func__,
7871da177e4SLinus Torvalds 			sl->name, sl);
7889fcbbac5SDavid Fries 
7899fcbbac5SDavid Fries 		list_del(&sl->w1_slave_entry);
7909fcbbac5SDavid Fries 
7919fcbbac5SDavid Fries 		memset(&msg, 0, sizeof(msg));
7929fcbbac5SDavid Fries 		memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id));
7931da177e4SLinus Torvalds 		msg.type = W1_SLAVE_REMOVE;
7941da177e4SLinus Torvalds 		w1_netlink_send(sl->master, &msg);
7959fcbbac5SDavid Fries 
7969fcbbac5SDavid Fries 		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl);
7971da177e4SLinus Torvalds 		device_unregister(&sl->dev);
7983aca692dSEvgeniy Polyakov 		#ifdef DEBUG
7991da177e4SLinus Torvalds 		memset(sl, 0, sizeof(*sl));
80012003375SEvgeniy Polyakov 		#endif
80112003375SEvgeniy Polyakov 		kfree(sl);
8021da177e4SLinus Torvalds 	}
8031da177e4SLinus Torvalds 	atomic_dec(&dev->refcnt);
8043aca692dSEvgeniy Polyakov 	mutex_unlock(&dev->list_mutex);
80518d7f891SDavid Fries 	return refcnt;
8063aca692dSEvgeniy Polyakov }
8079fcbbac5SDavid Fries 
w1_slave_detach(struct w1_slave * sl)8089fcbbac5SDavid Fries int w1_slave_detach(struct w1_slave *sl)
8099fcbbac5SDavid Fries {
8103aca692dSEvgeniy Polyakov 	/* Only detach a slave once as it decreases the refcnt each time. */
8111da177e4SLinus Torvalds 	int destroy_now;
8129fcbbac5SDavid Fries 	mutex_lock(&sl->master->list_mutex);
8139fcbbac5SDavid Fries 	destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags);
8149fcbbac5SDavid Fries 	set_bit(W1_SLAVE_DETACH, &sl->flags);
8159fcbbac5SDavid Fries 	mutex_unlock(&sl->master->list_mutex);
8169fcbbac5SDavid Fries 
8179fcbbac5SDavid Fries 	if (destroy_now)
8189fcbbac5SDavid Fries 		destroy_now = !w1_unref_slave(sl);
8199fcbbac5SDavid Fries 	return destroy_now ? 0 : -EBUSY;
8209fcbbac5SDavid Fries }
8219fcbbac5SDavid Fries 
w1_search_master_id(u32 id)8229fcbbac5SDavid Fries struct w1_master *w1_search_master_id(u32 id)
8239fcbbac5SDavid Fries {
8249fcbbac5SDavid Fries 	struct w1_master *dev = NULL, *iter;
8259fcbbac5SDavid Fries 
8269fcbbac5SDavid Fries 	mutex_lock(&w1_mlock);
8279fcbbac5SDavid Fries 	list_for_each_entry(iter, &w1_masters, w1_master_entry) {
8289fcbbac5SDavid Fries 		if (iter->id == id) {
8299fcbbac5SDavid Fries 			dev = iter;
8301da177e4SLinus Torvalds 			atomic_inc(&iter->refcnt);
83112003375SEvgeniy Polyakov 			break;
83212003375SEvgeniy Polyakov 		}
83312003375SEvgeniy Polyakov 	}
83412003375SEvgeniy Polyakov 	mutex_unlock(&w1_mlock);
83512003375SEvgeniy Polyakov 
836abd52a13SEvgeniy Polyakov 	return dev;
83712003375SEvgeniy Polyakov }
83812003375SEvgeniy Polyakov 
w1_search_slave(struct w1_reg_num * id)83912003375SEvgeniy Polyakov struct w1_slave *w1_search_slave(struct w1_reg_num *id)
84012003375SEvgeniy Polyakov {
84112003375SEvgeniy Polyakov 	struct w1_master *dev;
84212003375SEvgeniy Polyakov 	struct w1_slave *sl = NULL, *iter;
84312003375SEvgeniy Polyakov 
844abd52a13SEvgeniy Polyakov 	mutex_lock(&w1_mlock);
84512003375SEvgeniy Polyakov 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
84612003375SEvgeniy Polyakov 		mutex_lock(&dev->list_mutex);
84712003375SEvgeniy Polyakov 		list_for_each_entry(iter, &dev->slist, w1_slave_entry) {
84812003375SEvgeniy Polyakov 			if (iter->reg_num.family == id->family &&
84912003375SEvgeniy Polyakov 			    iter->reg_num.id == id->id &&
85012003375SEvgeniy Polyakov 			    iter->reg_num.crc == id->crc) {
85112003375SEvgeniy Polyakov 				sl = iter;
85212003375SEvgeniy Polyakov 				atomic_inc(&dev->refcnt);
85312003375SEvgeniy Polyakov 				atomic_inc(&iter->refcnt);
85412003375SEvgeniy Polyakov 				break;
855abd52a13SEvgeniy Polyakov 			}
85612003375SEvgeniy Polyakov 		}
8579fcbbac5SDavid Fries 		mutex_unlock(&dev->list_mutex);
85812003375SEvgeniy Polyakov 
85912003375SEvgeniy Polyakov 		if (sl)
86012003375SEvgeniy Polyakov 			break;
86112003375SEvgeniy Polyakov 	}
86212003375SEvgeniy Polyakov 	mutex_unlock(&w1_mlock);
86312003375SEvgeniy Polyakov 
86412003375SEvgeniy Polyakov 	return sl;
86512003375SEvgeniy Polyakov }
86612003375SEvgeniy Polyakov 
w1_reconnect_slaves(struct w1_family * f,int attach)86712003375SEvgeniy Polyakov void w1_reconnect_slaves(struct w1_family *f, int attach)
8689fcbbac5SDavid Fries {
86912003375SEvgeniy Polyakov 	struct w1_slave *sl, *sln;
87012003375SEvgeniy Polyakov 	struct w1_master *dev;
87112003375SEvgeniy Polyakov 
87212003375SEvgeniy Polyakov 	mutex_lock(&w1_mlock);
873abd52a13SEvgeniy Polyakov 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
87412003375SEvgeniy Polyakov 		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
87512003375SEvgeniy Polyakov 			"for family %02x.\n", dev->name, f->fid);
87612003375SEvgeniy Polyakov 		mutex_lock(&dev->mutex);
87712003375SEvgeniy Polyakov 		mutex_lock(&dev->list_mutex);
878c30c9b15SDavid Fries 		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
8796adf87bdSEvgeniy Polyakov 			/* If it is a new family, slaves with the default
880c30c9b15SDavid Fries 			 * family driver and are that family will be
8816adf87bdSEvgeniy Polyakov 			 * connected.  If the family is going away, devices
8826adf87bdSEvgeniy Polyakov 			 * matching that family are reconneced.
883abd52a13SEvgeniy Polyakov 			 */
8846adf87bdSEvgeniy Polyakov 			if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
885c30c9b15SDavid Fries 				&& sl->reg_num.family == f->fid) ||
886c30c9b15SDavid Fries 				(!attach && sl->family->fid == f->fid)) {
887c30c9b15SDavid Fries 				struct w1_reg_num rn;
8889fcbbac5SDavid Fries 
889c30c9b15SDavid Fries 				mutex_unlock(&dev->list_mutex);
890c30c9b15SDavid Fries 				memcpy(&rn, &sl->reg_num, sizeof(rn));
891c30c9b15SDavid Fries 				/* If it was already in use let the automatic
892c30c9b15SDavid Fries 				 * scan pick it up again later.
893c30c9b15SDavid Fries 				 */
894c30c9b15SDavid Fries 				if (!w1_slave_detach(sl))
895c30c9b15SDavid Fries 					w1_attach_slave_device(dev, &rn);
896c30c9b15SDavid Fries 				mutex_lock(&dev->list_mutex);
897c30c9b15SDavid Fries 			}
898c30c9b15SDavid Fries 		}
899c30c9b15SDavid Fries 		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
9009fcbbac5SDavid Fries 			"has been finished.\n", dev->name);
901c30c9b15SDavid Fries 		mutex_unlock(&dev->list_mutex);
9029fcbbac5SDavid Fries 		mutex_unlock(&dev->mutex);
9039fcbbac5SDavid Fries 	}
9049fcbbac5SDavid Fries 	mutex_unlock(&w1_mlock);
9059fcbbac5SDavid Fries }
906c30c9b15SDavid Fries 
w1_addr_crc_is_valid(struct w1_master * dev,u64 rn)9079fcbbac5SDavid Fries static int w1_addr_crc_is_valid(struct w1_master *dev, u64 rn)
908c30c9b15SDavid Fries {
909c30c9b15SDavid Fries 	u64 rn_le = cpu_to_le64(rn);
910c30c9b15SDavid Fries 	struct w1_reg_num *tmp = (struct w1_reg_num *)&rn;
911c30c9b15SDavid Fries 	u8 crc;
9129fcbbac5SDavid Fries 
913c30c9b15SDavid Fries 	crc = w1_calc_crc8((u8 *)&rn_le, 7);
9146adf87bdSEvgeniy Polyakov 
915abd52a13SEvgeniy Polyakov 	/* quirk:
9166adf87bdSEvgeniy Polyakov 	 *   DS28E04 (1w eeprom) has strapping pins to change
9176adf87bdSEvgeniy Polyakov 	 *   address, but will not update the crc. So normal rules
918*48b7de66SChristian Vogel 	 *   for consistent w1 addresses are violated. We test
919*48b7de66SChristian Vogel 	 *   with the 7 LSBs of the address forced high.
920*48b7de66SChristian Vogel 	 *
921*48b7de66SChristian Vogel 	 *   (char*)&rn_le = { family, addr_lsb, ..., addr_msb, crc }.
922*48b7de66SChristian Vogel 	 */
923*48b7de66SChristian Vogel 	if (crc != tmp->crc && tmp->family == W1_FAMILY_DS28E04) {
924*48b7de66SChristian Vogel 		u64 corr_le = rn_le;
925*48b7de66SChristian Vogel 
926*48b7de66SChristian Vogel 		((u8 *)&corr_le)[1] |= 0x7f;
927*48b7de66SChristian Vogel 		crc = w1_calc_crc8((u8 *)&corr_le, 7);
928*48b7de66SChristian Vogel 
929*48b7de66SChristian Vogel 		dev_info(&dev->dev, "DS28E04 crc workaround on %02x.%012llx.%02x\n",
930*48b7de66SChristian Vogel 			tmp->family, (unsigned long long)tmp->id, tmp->crc);
931*48b7de66SChristian Vogel 	}
932*48b7de66SChristian Vogel 
933*48b7de66SChristian Vogel 	if (crc != tmp->crc) {
934*48b7de66SChristian Vogel 		dev_dbg(&dev->dev, "w1 addr crc mismatch: %02x.%012llx.%02x != 0x%02x.\n",
935*48b7de66SChristian Vogel 			tmp->family, (unsigned long long)tmp->id, tmp->crc, crc);
936*48b7de66SChristian Vogel 		return 0;
937*48b7de66SChristian Vogel 	}
938*48b7de66SChristian Vogel 	return 1;
939*48b7de66SChristian Vogel }
940*48b7de66SChristian Vogel 
w1_slave_found(struct w1_master * dev,u64 rn)941*48b7de66SChristian Vogel void w1_slave_found(struct w1_master *dev, u64 rn)
942*48b7de66SChristian Vogel {
943*48b7de66SChristian Vogel 	struct w1_slave *sl;
944*48b7de66SChristian Vogel 	struct w1_reg_num *tmp;
945*48b7de66SChristian Vogel 
946*48b7de66SChristian Vogel 	atomic_inc(&dev->refcnt);
947*48b7de66SChristian Vogel 
948*48b7de66SChristian Vogel 	tmp = (struct w1_reg_num *) &rn;
949*48b7de66SChristian Vogel 
950*48b7de66SChristian Vogel 	sl = w1_slave_search_device(dev, tmp);
951*48b7de66SChristian Vogel 	if (sl) {
952963bb101SDavid Fries 		set_bit(W1_SLAVE_ACTIVE, &sl->flags);
9531da177e4SLinus Torvalds 	} else {
9541da177e4SLinus Torvalds 		if (rn && w1_addr_crc_is_valid(dev, rn))
9551da177e4SLinus Torvalds 			w1_attach_slave_device(dev, tmp);
9561da177e4SLinus Torvalds 	}
957c30c9b15SDavid Fries 
9581da177e4SLinus Torvalds 	atomic_dec(&dev->refcnt);
9591da177e4SLinus Torvalds }
9601da177e4SLinus Torvalds 
961cd7b28d3SDavid Fries /**
962cd7b28d3SDavid Fries  * w1_search() - Performs a ROM Search & registers any devices found.
963bb670937SMichal Nazarewicz  * @dev: The master device to search
964cd7b28d3SDavid Fries  * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH
965*48b7de66SChristian Vogel  * to return only devices in the alarmed state
9668523ff45Sjohnpol@2ka.mipt.ru  * @cb: Function to call when a device is found
9671da177e4SLinus Torvalds  *
9681da177e4SLinus Torvalds  * The 1-wire search is a simple binary tree search.
9691da177e4SLinus Torvalds  * For each bit of the address, we read two bits and write one bit.
9701da177e4SLinus Torvalds  * The bit written will put to sleep all devies that don't match that bit.
9711da177e4SLinus Torvalds  * When the two reads differ, the direction choice is obvious.
9726b729861SEvgeniy Polyakov  * When both bits are 0, we must choose a path to take.
973b3be177aSDavid Fries  * When we can scan all 64 bits without having to choose a path, we are done.
974b3be177aSDavid Fries  *
975b3be177aSDavid Fries  * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
976b3be177aSDavid Fries  *
977b3be177aSDavid Fries  */
w1_search(struct w1_master * dev,u8 search_type,w1_slave_found_callback cb)978b3be177aSDavid Fries void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
9796b729861SEvgeniy Polyakov {
9806b729861SEvgeniy Polyakov 	u64 last_rn, rn, tmp64;
9816b729861SEvgeniy Polyakov 	int i, slave_count = 0;
9826b729861SEvgeniy Polyakov 	int last_zero, last_device;
9836b729861SEvgeniy Polyakov 	int search_bit, desc_bit;
9846b729861SEvgeniy Polyakov 	u8  triplet_ret = 0;
9856b729861SEvgeniy Polyakov 
9866b729861SEvgeniy Polyakov 	search_bit = 0;
9876b729861SEvgeniy Polyakov 	rn = dev->search_id;
9886b729861SEvgeniy Polyakov 	last_rn = 0;
98912003375SEvgeniy Polyakov 	last_device = 0;
9901da177e4SLinus Torvalds 	last_zero = -1;
9916b729861SEvgeniy Polyakov 
9926b729861SEvgeniy Polyakov 	desc_bit = 64;
9936b729861SEvgeniy Polyakov 
9946b729861SEvgeniy Polyakov 	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
9956b729861SEvgeniy Polyakov 		last_rn = rn;
9961da177e4SLinus Torvalds 		rn = 0;
9976b729861SEvgeniy Polyakov 
9983c6955e5SDavid Fries 		/*
9993c6955e5SDavid Fries 		 * Reset bus and all 1-wire device state machines
10006b729861SEvgeniy Polyakov 		 * so they can respond to our requests.
10016b729861SEvgeniy Polyakov 		 *
10021da177e4SLinus Torvalds 		 * Return 0 - device(s) present, 1 - no devices present.
10031da177e4SLinus Torvalds 		 */
10041da177e4SLinus Torvalds 		mutex_lock(&dev->bus_mutex);
10056b729861SEvgeniy Polyakov 		if (w1_reset_bus(dev)) {
10066b729861SEvgeniy Polyakov 			mutex_unlock(&dev->bus_mutex);
10071da177e4SLinus Torvalds 			dev_dbg(&dev->dev, "No devices present on the wire.\n");
10081da177e4SLinus Torvalds 			break;
10091da177e4SLinus Torvalds 		}
10101da177e4SLinus Torvalds 
10111da177e4SLinus Torvalds 		/* Do fast search on single slave bus */
10121da177e4SLinus Torvalds 		if (dev->max_slave_count == 1) {
10131da177e4SLinus Torvalds 			int rv;
10141da177e4SLinus Torvalds 			w1_write_8(dev, W1_READ_ROM);
1015b02f8bedSNeilBrown 			rv = w1_read_block(dev, (u8 *)&rn, 8);
10161da177e4SLinus Torvalds 			mutex_unlock(&dev->bus_mutex);
1017b02f8bedSNeilBrown 
10182da5bf80SEvgeniy Polyakov 			if (rv == 8 && rn)
10191da177e4SLinus Torvalds 				cb(dev, rn);
10201da177e4SLinus Torvalds 
10211da177e4SLinus Torvalds 			break;
1022c9cbf558SEvgeniy Polyakov 		}
1023c9cbf558SEvgeniy Polyakov 
1024b02f8bedSNeilBrown 		/* Start the search */
1025c9cbf558SEvgeniy Polyakov 		w1_write_8(dev, search_type);
1026b02f8bedSNeilBrown 		for (i = 0; i < 64; ++i) {
1027b02f8bedSNeilBrown 			/* Determine the direction/search bit */
1028c9cbf558SEvgeniy Polyakov 			if (i == desc_bit)
1029b02f8bedSNeilBrown 				search_bit = 1;	  /* took the 0 path last time, so take the 1 path */
1030c9cbf558SEvgeniy Polyakov 			else if (i > desc_bit)
1031c9cbf558SEvgeniy Polyakov 				search_bit = 0;	  /* take the 0 path on the next branch */
1032c9cbf558SEvgeniy Polyakov 			else
1033c9cbf558SEvgeniy Polyakov 				search_bit = ((last_rn >> i) & 0x1);
1034c9cbf558SEvgeniy Polyakov 
10356b729861SEvgeniy Polyakov 			/* Read two bits and write one bit */
103612003375SEvgeniy Polyakov 			triplet_ret = w1_triplet(dev, search_bit);
10371da177e4SLinus Torvalds 
10386b729861SEvgeniy Polyakov 			/* quit if no device responded */
10396b729861SEvgeniy Polyakov 			if ( (triplet_ret & 0x03) == 0x03 )
10406b729861SEvgeniy Polyakov 				break;
10416b729861SEvgeniy Polyakov 
10426b729861SEvgeniy Polyakov 			/* If both directions were valid, and we took the 0 path... */
10436b729861SEvgeniy Polyakov 			if (triplet_ret == 0)
10446b729861SEvgeniy Polyakov 				last_zero = i;
10451da177e4SLinus Torvalds 
1046b3be177aSDavid Fries 			/* extract the direction taken & update the device number */
10476b729861SEvgeniy Polyakov 			tmp64 = (triplet_ret >> 2);
10486b729861SEvgeniy Polyakov 			rn |= (tmp64 << i);
10496b729861SEvgeniy Polyakov 
10506b729861SEvgeniy Polyakov 			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
10511da177e4SLinus Torvalds 				mutex_unlock(&dev->bus_mutex);
10521da177e4SLinus Torvalds 				dev_dbg(&dev->dev, "Abort w1_search\n");
10536b729861SEvgeniy Polyakov 				return;
10546b729861SEvgeniy Polyakov 			}
10551da177e4SLinus Torvalds 		}
10566b729861SEvgeniy Polyakov 		mutex_unlock(&dev->bus_mutex);
10576b729861SEvgeniy Polyakov 
10586b729861SEvgeniy Polyakov 		if ( (triplet_ret & 0x03) != 0x03 ) {
10596b729861SEvgeniy Polyakov 			if ((desc_bit == last_zero) || (last_zero < 0)) {
10600d671b27SDavid Fries 				last_device = 1;
106142105698SDavid Fries 				dev->search_id = 0;
1062b02f8bedSNeilBrown 			} else {
10637dc8f527SDavid Fries 				dev->search_id = rn;
10640d671b27SDavid Fries 			}
10650d671b27SDavid Fries 			desc_bit = last_zero;
10661da177e4SLinus Torvalds 			cb(dev, rn);
1067b02f8bedSNeilBrown 		}
10681da177e4SLinus Torvalds 
10696b729861SEvgeniy Polyakov 		if (!last_device && slave_count == dev->max_slave_count &&
10703c6955e5SDavid Fries 			!test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
10711da177e4SLinus Torvalds 			/* Only max_slave_count will be scanned in a search,
10723c6955e5SDavid Fries 			 * but it will start where it left off next search
10733c6955e5SDavid Fries 			 * until all ids are identified and then it will start
10743c6955e5SDavid Fries 			 * over.  A continued search will report the previous
10753c6955e5SDavid Fries 			 * last id as the first id (provided it is still on the
10761da177e4SLinus Torvalds 			 * bus).
1077c30c9b15SDavid Fries 			 */
10786b729861SEvgeniy Polyakov 			dev_info(&dev->dev, "%s: max_slave_count %d reached, "
1079a1613056SDavid Fries 				"will continue next search.\n", __func__,
1080a1613056SDavid Fries 				dev->max_slave_count);
1081a1613056SDavid Fries 			set_bit(W1_WARN_MAX_COUNT, &dev->flags);
10823c6955e5SDavid Fries 		}
10833c6955e5SDavid Fries 	}
10843c6955e5SDavid Fries }
10853c6955e5SDavid Fries 
w1_search_process_cb(struct w1_master * dev,u8 search_type,w1_slave_found_callback cb)10863c6955e5SDavid Fries void w1_search_process_cb(struct w1_master *dev, u8 search_type,
10873c6955e5SDavid Fries 	w1_slave_found_callback cb)
10883c6955e5SDavid Fries {
1089a1613056SDavid Fries 	struct w1_slave *sl, *sln;
10903c6955e5SDavid Fries 
1091a1613056SDavid Fries 	mutex_lock(&dev->list_mutex);
1092a1613056SDavid Fries 	list_for_each_entry(sl, &dev->slist, w1_slave_entry)
1093a1613056SDavid Fries 		clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
10941da177e4SLinus Torvalds 	mutex_unlock(&dev->list_mutex);
10951da177e4SLinus Torvalds 
10961da177e4SLinus Torvalds 	w1_search_devices(dev, search_type, cb);
1097963bb101SDavid Fries 
1098963bb101SDavid Fries 	mutex_lock(&dev->list_mutex);
109912003375SEvgeniy Polyakov 	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
110012003375SEvgeniy Polyakov 		if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
110112003375SEvgeniy Polyakov 			mutex_unlock(&dev->list_mutex);
11029fcbbac5SDavid Fries 			w1_slave_detach(sl);
110312003375SEvgeniy Polyakov 			mutex_lock(&dev->list_mutex);
1104bb670937SMichal Nazarewicz 		}
11059fcbbac5SDavid Fries 		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
110612003375SEvgeniy Polyakov 			sl->ttl = dev->slave_ttl;
1107963bb101SDavid Fries 	}
110812003375SEvgeniy Polyakov 	mutex_unlock(&dev->list_mutex);
11099fcbbac5SDavid Fries 
111012003375SEvgeniy Polyakov 	if (dev->search_count > 0)
11119fcbbac5SDavid Fries 		dev->search_count--;
11129fcbbac5SDavid Fries }
111312003375SEvgeniy Polyakov 
w1_search_process(struct w1_master * dev,u8 search_type)11149fcbbac5SDavid Fries static void w1_search_process(struct w1_master *dev, u8 search_type)
11159fcbbac5SDavid Fries {
1116bb670937SMichal Nazarewicz 	w1_search_process_cb(dev, search_type, w1_slave_found);
111712003375SEvgeniy Polyakov }
111812003375SEvgeniy Polyakov 
11199fcbbac5SDavid Fries /**
112012003375SEvgeniy Polyakov  * w1_process_callbacks() - execute each dev->async_list callback entry
112112003375SEvgeniy Polyakov  * @dev: w1_master device
112212003375SEvgeniy Polyakov  *
112312003375SEvgeniy Polyakov  * The w1 master list_mutex must be held.
112412003375SEvgeniy Polyakov  *
1125963bb101SDavid Fries  * Return: 1 if there were commands to executed 0 otherwise
1126963bb101SDavid Fries  */
w1_process_callbacks(struct w1_master * dev)1127963bb101SDavid Fries int w1_process_callbacks(struct w1_master *dev)
1128963bb101SDavid Fries {
1129963bb101SDavid Fries 	int ret = 0;
1130b3be177aSDavid Fries 	struct w1_async_cmd *async_cmd, *async_n;
1131b3be177aSDavid Fries 
1132b3be177aSDavid Fries 	/* The list can be added to in another thread, loop until it is empty */
1133b3be177aSDavid Fries 	while (!list_empty(&dev->async_list)) {
1134a0f10464SAlexey Khoroshilov 		list_for_each_entry_safe(async_cmd, async_n, &dev->async_list,
1135a0f10464SAlexey Khoroshilov 			async_entry) {
1136b3be177aSDavid Fries 			/* drop the lock, if it is a search it can take a long
1137b3be177aSDavid Fries 			 * time */
11389fcbbac5SDavid Fries 			mutex_unlock(&dev->list_mutex);
11399fcbbac5SDavid Fries 			async_cmd->cb(dev, async_cmd);
11409fcbbac5SDavid Fries 			ret = 1;
11419fcbbac5SDavid Fries 			mutex_lock(&dev->list_mutex);
11429fcbbac5SDavid Fries 		}
11439fcbbac5SDavid Fries 	}
11449fcbbac5SDavid Fries 	return ret;
11459fcbbac5SDavid Fries }
11469fcbbac5SDavid Fries 
w1_process(void * data)11479fcbbac5SDavid Fries int w1_process(void *data)
11489fcbbac5SDavid Fries {
11499fcbbac5SDavid Fries 	struct w1_master *dev = (struct w1_master *) data;
11509fcbbac5SDavid Fries 	/* As long as w1_timeout is only set by a module parameter the sleep
11519fcbbac5SDavid Fries 	 * time can be calculated in jiffies once.
11529fcbbac5SDavid Fries 	 */
11539fcbbac5SDavid Fries 	const unsigned long jtime =
11549fcbbac5SDavid Fries 	  usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us);
11559fcbbac5SDavid Fries 	/* remainder if it woke up early */
11569fcbbac5SDavid Fries 	unsigned long jremain = 0;
11579fcbbac5SDavid Fries 
11581da177e4SLinus Torvalds 	atomic_inc(&dev->refcnt);
11591da177e4SLinus Torvalds 
11601da177e4SLinus Torvalds 	for (;;) {
11613c52e4e6SDavid Fries 
11623c52e4e6SDavid Fries 		if (!jremain && dev->search_count) {
11633c52e4e6SDavid Fries 			mutex_lock(&dev->mutex);
1164c3098356SDmitry Khromov 			w1_search_process(dev, W1_SEARCH);
1165c3098356SDmitry Khromov 			mutex_unlock(&dev->mutex);
11669fcbbac5SDavid Fries 		}
11679fcbbac5SDavid Fries 
11681da177e4SLinus Torvalds 		mutex_lock(&dev->list_mutex);
11699fcbbac5SDavid Fries 		/* Note, w1_process_callback drops the lock while processing,
11709fcbbac5SDavid Fries 		 * but locks it again before returning.
11719fcbbac5SDavid Fries 		 */
1172abd52a13SEvgeniy Polyakov 		if (!w1_process_callbacks(dev) && jremain) {
117312003375SEvgeniy Polyakov 			/* a wake up is either to stop the thread, process
1174abd52a13SEvgeniy Polyakov 			 * callbacks, or search, it isn't process callbacks, so
11751da177e4SLinus Torvalds 			 * schedule a search.
11761da177e4SLinus Torvalds 			 */
11779fcbbac5SDavid Fries 			jremain = 1;
11789fcbbac5SDavid Fries 		}
11799fcbbac5SDavid Fries 
11809fcbbac5SDavid Fries 		__set_current_state(TASK_INTERRUPTIBLE);
11819fcbbac5SDavid Fries 
11829fcbbac5SDavid Fries 		/* hold list_mutex until after interruptible to prevent loosing
11839fcbbac5SDavid Fries 		 * the wakeup signal when async_cmd is added.
11849fcbbac5SDavid Fries 		 */
11859fcbbac5SDavid Fries 		mutex_unlock(&dev->list_mutex);
11869fcbbac5SDavid Fries 
11879fcbbac5SDavid Fries 		if (kthread_should_stop()) {
11889fcbbac5SDavid Fries 			__set_current_state(TASK_RUNNING);
11893c52e4e6SDavid Fries 			break;
11903c52e4e6SDavid Fries 		}
11919fcbbac5SDavid Fries 
11929fcbbac5SDavid Fries 		/* Only sleep when the search is active. */
11939fcbbac5SDavid Fries 		if (dev->search_count) {
11949fcbbac5SDavid Fries 			if (!jremain)
11959fcbbac5SDavid Fries 				jremain = jtime;
11963c52e4e6SDavid Fries 			jremain = schedule_timeout(jremain);
11973c52e4e6SDavid Fries 		}
11983c52e4e6SDavid Fries 		else
11993c52e4e6SDavid Fries 			schedule();
12009fcbbac5SDavid Fries 	}
12019fcbbac5SDavid Fries 
12029fcbbac5SDavid Fries 	atomic_dec(&dev->refcnt);
12039fcbbac5SDavid Fries 
12049fcbbac5SDavid Fries 	return 0;
12053c52e4e6SDavid Fries }
12063c52e4e6SDavid Fries 
w1_init(void)120701e14d6dSDavid Fries static int __init w1_init(void)
120801e14d6dSDavid Fries {
12091da177e4SLinus Torvalds 	int retval;
12101da177e4SLinus Torvalds 
12111da177e4SLinus Torvalds 	pr_info("Driver for 1-wire Dallas network protocol.\n");
12121da177e4SLinus Torvalds 
12131da177e4SLinus Torvalds 	w1_init_netlink();
121473a98fceSPeter Huewe 
12151da177e4SLinus Torvalds 	retval = bus_register(&w1_bus_type);
12161da177e4SLinus Torvalds 	if (retval) {
12171da177e4SLinus Torvalds 		pr_err("Failed to register bus. err=%d.\n", retval);
1218fdc9167aSFjodor Schelichow 		goto err_out_exit_init;
12191da177e4SLinus Torvalds 	}
122012003375SEvgeniy Polyakov 
122112003375SEvgeniy Polyakov 	retval = driver_register(&w1_master_driver);
12221da177e4SLinus Torvalds 	if (retval) {
12231da177e4SLinus Torvalds 		pr_err("Failed to register master driver. err=%d.\n",
1224fdc9167aSFjodor Schelichow 			retval);
12251da177e4SLinus Torvalds 		goto err_out_bus_unregister;
12261da177e4SLinus Torvalds 	}
12271da177e4SLinus Torvalds 
12287f772ed8SEvgeniy Polyakov 	retval = driver_register(&w1_slave_driver);
12291da177e4SLinus Torvalds 	if (retval) {
1230fdc9167aSFjodor Schelichow 		pr_err("Failed to register slave driver. err=%d.\n",
12311da177e4SLinus Torvalds 			retval);
12321da177e4SLinus Torvalds 		goto err_out_master_unregister;
12331da177e4SLinus Torvalds 	}
12341da177e4SLinus Torvalds 
12357f772ed8SEvgeniy Polyakov 	return 0;
12367f772ed8SEvgeniy Polyakov 
1237fdc9167aSFjodor Schelichow #if 0
12387f772ed8SEvgeniy Polyakov /* For undoing the slave register if there was a step after it. */
12397f772ed8SEvgeniy Polyakov err_out_slave_unregister:
12407f772ed8SEvgeniy Polyakov 	driver_unregister(&w1_slave_driver);
12417f772ed8SEvgeniy Polyakov #endif
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds err_out_master_unregister:
1244c30c9b15SDavid Fries 	driver_unregister(&w1_master_driver);
1245c30c9b15SDavid Fries 
12467f772ed8SEvgeniy Polyakov err_out_bus_unregister:
12477f772ed8SEvgeniy Polyakov 	bus_unregister(&w1_bus_type);
1248c30c9b15SDavid Fries 
12497f772ed8SEvgeniy Polyakov err_out_exit_init:
12507f772ed8SEvgeniy Polyakov 	return retval;
12517f772ed8SEvgeniy Polyakov }
12521da177e4SLinus Torvalds 
w1_fini(void)12531da177e4SLinus Torvalds static void __exit w1_fini(void)
12541da177e4SLinus Torvalds {
12551da177e4SLinus Torvalds 	struct w1_master *dev, *n;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	/* Set netlink removal messages and some cleanup */
12581da177e4SLinus Torvalds 	list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry)
12591da177e4SLinus Torvalds 		__w1_remove_master_device(dev);
126073a98fceSPeter Huewe 
12611da177e4SLinus Torvalds 	w1_fini_netlink();
12621da177e4SLinus Torvalds 
12631da177e4SLinus Torvalds 	driver_unregister(&w1_slave_driver);
1264c30c9b15SDavid Fries 	driver_unregister(&w1_master_driver);
12657785925dSEvgeniy Polyakov 	bus_unregister(&w1_bus_type);
12661da177e4SLinus Torvalds }
12671da177e4SLinus Torvalds 
126812003375SEvgeniy Polyakov module_init(w1_init);
126912003375SEvgeniy Polyakov module_exit(w1_fini);
12707f772ed8SEvgeniy Polyakov 
12717f772ed8SEvgeniy Polyakov MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
12721da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
12731da177e4SLinus Torvalds MODULE_LICENSE("GPL");
12741da177e4SLinus Torvalds