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