xref: /openbmc/linux/drivers/w1/w1.c (revision d2a4ef6a0ce4d841293b49bf2cdc17a0ebfaaf9d)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *	w1.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
91da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
101da177e4SLinus Torvalds  * (at your option) any later version.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
131da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4SLinus Torvalds  * GNU General Public License for more details.
161da177e4SLinus Torvalds  *
171da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
181da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
191da177e4SLinus Torvalds  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
201da177e4SLinus Torvalds  */
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds #include <linux/delay.h>
231da177e4SLinus Torvalds #include <linux/kernel.h>
241da177e4SLinus Torvalds #include <linux/module.h>
251da177e4SLinus Torvalds #include <linux/moduleparam.h>
261da177e4SLinus Torvalds #include <linux/list.h>
271da177e4SLinus Torvalds #include <linux/interrupt.h>
281da177e4SLinus Torvalds #include <linux/spinlock.h>
291da177e4SLinus Torvalds #include <linux/timer.h>
301da177e4SLinus Torvalds #include <linux/device.h>
311da177e4SLinus Torvalds #include <linux/slab.h>
321da177e4SLinus Torvalds #include <linux/sched.h>
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds #include <asm/atomic.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include "w1.h"
371da177e4SLinus Torvalds #include "w1_io.h"
381da177e4SLinus Torvalds #include "w1_log.h"
391da177e4SLinus Torvalds #include "w1_int.h"
401da177e4SLinus Torvalds #include "w1_family.h"
411da177e4SLinus Torvalds #include "w1_netlink.h"
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds MODULE_LICENSE("GPL");
441da177e4SLinus Torvalds MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
451da177e4SLinus Torvalds MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds static int w1_timeout = 10;
481da177e4SLinus Torvalds int w1_max_slave_count = 10;
491da177e4SLinus Torvalds int w1_max_slave_ttl = 10;
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds module_param_named(timeout, w1_timeout, int, 0);
521da177e4SLinus Torvalds module_param_named(max_slave_count, w1_max_slave_count, int, 0);
531da177e4SLinus Torvalds module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds DEFINE_SPINLOCK(w1_mlock);
561da177e4SLinus Torvalds LIST_HEAD(w1_masters);
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds static pid_t control_thread;
591da177e4SLinus Torvalds static int control_needs_exit;
601da177e4SLinus Torvalds static DECLARE_COMPLETION(w1_control_complete);
611da177e4SLinus Torvalds 
621da177e4SLinus Torvalds static int w1_master_match(struct device *dev, struct device_driver *drv)
631da177e4SLinus Torvalds {
641da177e4SLinus Torvalds 	return 1;
651da177e4SLinus Torvalds }
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds static int w1_master_probe(struct device *dev)
681da177e4SLinus Torvalds {
691da177e4SLinus Torvalds 	return -ENODEV;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds static int w1_master_remove(struct device *dev)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	return 0;
751da177e4SLinus Torvalds }
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds static void w1_master_release(struct device *dev)
781da177e4SLinus Torvalds {
79db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
801da177e4SLinus Torvalds 	complete(&md->dev_released);
811da177e4SLinus Torvalds }
821da177e4SLinus Torvalds 
831da177e4SLinus Torvalds static void w1_slave_release(struct device *dev)
841da177e4SLinus Torvalds {
85db2d0008SEvgeniy Polyakov 	struct w1_slave *sl = dev_to_w1_slave(dev);
861da177e4SLinus Torvalds 	complete(&sl->dev_released);
871da177e4SLinus Torvalds }
881da177e4SLinus Torvalds 
89*d2a4ef6aSEvgeniy Polyakov static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *attr, char *buf)
901da177e4SLinus Torvalds {
91*d2a4ef6aSEvgeniy Polyakov       struct w1_slave *sl = dev_to_w1_slave(dev);
92*d2a4ef6aSEvgeniy Polyakov 
93*d2a4ef6aSEvgeniy Polyakov       return sprintf(buf, "%s\n", sl->name);
941da177e4SLinus Torvalds }
951da177e4SLinus Torvalds 
96*d2a4ef6aSEvgeniy Polyakov static ssize_t w1_slave_read_id(struct kobject *kobj, char *buf, loff_t off, size_t count)
971da177e4SLinus Torvalds {
98*d2a4ef6aSEvgeniy Polyakov       struct w1_slave *sl = kobj_to_w1_slave(kobj);
99*d2a4ef6aSEvgeniy Polyakov 
100*d2a4ef6aSEvgeniy Polyakov       atomic_inc(&sl->refcnt);
101*d2a4ef6aSEvgeniy Polyakov       if (off > 8) {
102*d2a4ef6aSEvgeniy Polyakov               count = 0;
103*d2a4ef6aSEvgeniy Polyakov 	} else {
104*d2a4ef6aSEvgeniy Polyakov 		if (off + count > 8)
105*d2a4ef6aSEvgeniy Polyakov 			count = 8 - off;
106*d2a4ef6aSEvgeniy Polyakov 
107*d2a4ef6aSEvgeniy Polyakov 		memcpy(buf, (u8 *)&sl->reg_num, count);
108*d2a4ef6aSEvgeniy Polyakov 	}
109*d2a4ef6aSEvgeniy Polyakov 	atomic_dec(&sl->refcnt);
110*d2a4ef6aSEvgeniy Polyakov 
111*d2a4ef6aSEvgeniy Polyakov 	return count;
1121da177e4SLinus Torvalds   }
1131da177e4SLinus Torvalds 
114*d2a4ef6aSEvgeniy Polyakov static struct device_attribute w1_slave_attr_name =
115*d2a4ef6aSEvgeniy Polyakov 	__ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
1167785925dSEvgeniy Polyakov 
117*d2a4ef6aSEvgeniy Polyakov static struct bin_attribute w1_slave_attr_bin_id = {
1187785925dSEvgeniy Polyakov       .attr = {
119*d2a4ef6aSEvgeniy Polyakov               .name = "id",
1207785925dSEvgeniy Polyakov               .mode = S_IRUGO,
1217785925dSEvgeniy Polyakov               .owner = THIS_MODULE,
1227785925dSEvgeniy Polyakov       },
123*d2a4ef6aSEvgeniy Polyakov       .size = 8,
124*d2a4ef6aSEvgeniy Polyakov       .read = w1_slave_read_id,
1257785925dSEvgeniy Polyakov };
1267785925dSEvgeniy Polyakov 
127*d2a4ef6aSEvgeniy Polyakov /* Default family */
128*d2a4ef6aSEvgeniy Polyakov static struct w1_family w1_default_family;
129*d2a4ef6aSEvgeniy Polyakov 
1307f772ed8SEvgeniy Polyakov static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
1317785925dSEvgeniy Polyakov 
1321da177e4SLinus Torvalds static struct bus_type w1_bus_type = {
1331da177e4SLinus Torvalds 	.name = "w1",
1341da177e4SLinus Torvalds 	.match = w1_master_match,
1357f772ed8SEvgeniy Polyakov 	.hotplug = w1_hotplug,
1361da177e4SLinus Torvalds };
1371da177e4SLinus Torvalds 
1387f772ed8SEvgeniy Polyakov struct device_driver w1_master_driver = {
1397f772ed8SEvgeniy Polyakov 	.name = "w1_master_driver",
1401da177e4SLinus Torvalds 	.bus = &w1_bus_type,
1411da177e4SLinus Torvalds 	.probe = w1_master_probe,
1421da177e4SLinus Torvalds 	.remove = w1_master_remove,
1431da177e4SLinus Torvalds };
1441da177e4SLinus Torvalds 
1457f772ed8SEvgeniy Polyakov struct device w1_master_device = {
1461da177e4SLinus Torvalds 	.parent = NULL,
1471da177e4SLinus Torvalds 	.bus = &w1_bus_type,
1481da177e4SLinus Torvalds 	.bus_id = "w1 bus master",
1497f772ed8SEvgeniy Polyakov 	.driver = &w1_master_driver,
1501da177e4SLinus Torvalds 	.release = &w1_master_release
1511da177e4SLinus Torvalds };
1521da177e4SLinus Torvalds 
1537f772ed8SEvgeniy Polyakov struct device_driver w1_slave_driver = {
1547f772ed8SEvgeniy Polyakov 	.name = "w1_slave_driver",
1557f772ed8SEvgeniy Polyakov 	.bus = &w1_bus_type,
1567f772ed8SEvgeniy Polyakov };
1577f772ed8SEvgeniy Polyakov 
1587f772ed8SEvgeniy Polyakov struct device w1_slave_device = {
1597f772ed8SEvgeniy Polyakov 	.parent = NULL,
1607f772ed8SEvgeniy Polyakov 	.bus = &w1_bus_type,
1617f772ed8SEvgeniy Polyakov 	.bus_id = "w1 bus slave",
1627f772ed8SEvgeniy Polyakov 	.driver = &w1_slave_driver,
1637f772ed8SEvgeniy Polyakov };
1647f772ed8SEvgeniy Polyakov 
165060b8845SYani Ioannou static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
1661da177e4SLinus Torvalds {
167db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
1681da177e4SLinus Torvalds 	ssize_t count;
1691da177e4SLinus Torvalds 
1701da177e4SLinus Torvalds 	if (down_interruptible (&md->mutex))
1711da177e4SLinus Torvalds 		return -EBUSY;
1721da177e4SLinus Torvalds 
1731da177e4SLinus Torvalds 	count = sprintf(buf, "%s\n", md->name);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	up(&md->mutex);
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds 	return count;
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds 
1802a9d0c17SEvgeniy Polyakov static ssize_t w1_master_attribute_store_search(struct device * dev,
1812a9d0c17SEvgeniy Polyakov 						struct device_attribute *attr,
1822a9d0c17SEvgeniy Polyakov 						const char * buf, size_t count)
1832a9d0c17SEvgeniy Polyakov {
184db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
1852a9d0c17SEvgeniy Polyakov 
1862a9d0c17SEvgeniy Polyakov 	if (down_interruptible (&md->mutex))
1872a9d0c17SEvgeniy Polyakov 		return -EBUSY;
1882a9d0c17SEvgeniy Polyakov 
1892a9d0c17SEvgeniy Polyakov 	md->search_count = simple_strtol(buf, NULL, 0);
1902a9d0c17SEvgeniy Polyakov 
1912a9d0c17SEvgeniy Polyakov 	up(&md->mutex);
1922a9d0c17SEvgeniy Polyakov 
1932a9d0c17SEvgeniy Polyakov 	return count;
1942a9d0c17SEvgeniy Polyakov }
1952a9d0c17SEvgeniy Polyakov 
1962a9d0c17SEvgeniy Polyakov static ssize_t w1_master_attribute_show_search(struct device *dev,
1972a9d0c17SEvgeniy Polyakov 					       struct device_attribute *attr,
1982a9d0c17SEvgeniy Polyakov 					       char *buf)
1992a9d0c17SEvgeniy Polyakov {
200db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2012a9d0c17SEvgeniy Polyakov 	ssize_t count;
2022a9d0c17SEvgeniy Polyakov 
2032a9d0c17SEvgeniy Polyakov 	if (down_interruptible (&md->mutex))
2042a9d0c17SEvgeniy Polyakov 		return -EBUSY;
2052a9d0c17SEvgeniy Polyakov 
2062a9d0c17SEvgeniy Polyakov 	count = sprintf(buf, "%d\n", md->search_count);
2072a9d0c17SEvgeniy Polyakov 
2082a9d0c17SEvgeniy Polyakov 	up(&md->mutex);
2092a9d0c17SEvgeniy Polyakov 
2102a9d0c17SEvgeniy Polyakov 	return count;
2112a9d0c17SEvgeniy Polyakov }
2122a9d0c17SEvgeniy Polyakov 
213060b8845SYani Ioannou static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
2141da177e4SLinus Torvalds {
215db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2161da177e4SLinus Torvalds 	ssize_t count;
2171da177e4SLinus Torvalds 
2181da177e4SLinus Torvalds 	if (down_interruptible(&md->mutex))
2191da177e4SLinus Torvalds 		return -EBUSY;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	count = sprintf(buf, "0x%p\n", md->bus_master);
2221da177e4SLinus Torvalds 
2231da177e4SLinus Torvalds 	up(&md->mutex);
2241da177e4SLinus Torvalds 	return count;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
227060b8845SYani Ioannou static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	ssize_t count;
2301da177e4SLinus Torvalds 	count = sprintf(buf, "%d\n", w1_timeout);
2311da177e4SLinus Torvalds 	return count;
2321da177e4SLinus Torvalds }
2331da177e4SLinus Torvalds 
234060b8845SYani Ioannou static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
2351da177e4SLinus Torvalds {
236db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2371da177e4SLinus Torvalds 	ssize_t count;
2381da177e4SLinus Torvalds 
2391da177e4SLinus Torvalds 	if (down_interruptible(&md->mutex))
2401da177e4SLinus Torvalds 		return -EBUSY;
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds 	count = sprintf(buf, "%d\n", md->max_slave_count);
2431da177e4SLinus Torvalds 
2441da177e4SLinus Torvalds 	up(&md->mutex);
2451da177e4SLinus Torvalds 	return count;
2461da177e4SLinus Torvalds }
2471da177e4SLinus Torvalds 
248060b8845SYani Ioannou static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
2491da177e4SLinus Torvalds {
250db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2511da177e4SLinus Torvalds 	ssize_t count;
2521da177e4SLinus Torvalds 
2531da177e4SLinus Torvalds 	if (down_interruptible(&md->mutex))
2541da177e4SLinus Torvalds 		return -EBUSY;
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds 	count = sprintf(buf, "%lu\n", md->attempts);
2571da177e4SLinus Torvalds 
2581da177e4SLinus Torvalds 	up(&md->mutex);
2591da177e4SLinus Torvalds 	return count;
2601da177e4SLinus Torvalds }
2611da177e4SLinus Torvalds 
262060b8845SYani Ioannou static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
2631da177e4SLinus Torvalds {
264db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2651da177e4SLinus Torvalds 	ssize_t count;
2661da177e4SLinus Torvalds 
2671da177e4SLinus Torvalds 	if (down_interruptible(&md->mutex))
2681da177e4SLinus Torvalds 		return -EBUSY;
2691da177e4SLinus Torvalds 
2701da177e4SLinus Torvalds 	count = sprintf(buf, "%d\n", md->slave_count);
2711da177e4SLinus Torvalds 
2721da177e4SLinus Torvalds 	up(&md->mutex);
2731da177e4SLinus Torvalds 	return count;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
276060b8845SYani Ioannou static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
2771da177e4SLinus Torvalds {
278db2d0008SEvgeniy Polyakov 	struct w1_master *md = dev_to_w1_master(dev);
2791da177e4SLinus Torvalds 	int c = PAGE_SIZE;
2801da177e4SLinus Torvalds 
2811da177e4SLinus Torvalds 	if (down_interruptible(&md->mutex))
2821da177e4SLinus Torvalds 		return -EBUSY;
2831da177e4SLinus Torvalds 
2841da177e4SLinus Torvalds 	if (md->slave_count == 0)
2851da177e4SLinus Torvalds 		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.\n");
2861da177e4SLinus Torvalds 	else {
2871da177e4SLinus Torvalds 		struct list_head *ent, *n;
2881da177e4SLinus Torvalds 		struct w1_slave *sl;
2891da177e4SLinus Torvalds 
2901da177e4SLinus Torvalds 		list_for_each_safe(ent, n, &md->slist) {
2911da177e4SLinus Torvalds 			sl = list_entry(ent, struct w1_slave, w1_slave_entry);
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds 			c -= snprintf(buf + PAGE_SIZE - c, c, "%s\n", sl->name);
2941da177e4SLinus Torvalds 		}
2951da177e4SLinus Torvalds 	}
2961da177e4SLinus Torvalds 
2971da177e4SLinus Torvalds 	up(&md->mutex);
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	return PAGE_SIZE - c;
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds 
3027785925dSEvgeniy Polyakov #define W1_MASTER_ATTR_RO(_name, _mode)				\
3037785925dSEvgeniy Polyakov 	struct device_attribute w1_master_attribute_##_name =	\
3047785925dSEvgeniy Polyakov 		__ATTR(w1_master_##_name, _mode,		\
3057785925dSEvgeniy Polyakov 		       w1_master_attribute_show_##_name, NULL)
3067785925dSEvgeniy Polyakov 
3072a9d0c17SEvgeniy Polyakov #define W1_MASTER_ATTR_RW(_name, _mode)				\
3082a9d0c17SEvgeniy Polyakov 	struct device_attribute w1_master_attribute_##_name =	\
3092a9d0c17SEvgeniy Polyakov 		__ATTR(w1_master_##_name, _mode,		\
3102a9d0c17SEvgeniy Polyakov 		       w1_master_attribute_show_##_name,	\
3112a9d0c17SEvgeniy Polyakov 		       w1_master_attribute_store_##_name)
3122a9d0c17SEvgeniy Polyakov 
3137785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(name, S_IRUGO);
3147785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
3157785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
3167785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(max_slave_count, S_IRUGO);
3177785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
3187785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
3197785925dSEvgeniy Polyakov static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
3202a9d0c17SEvgeniy Polyakov static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
3217785925dSEvgeniy Polyakov 
3227785925dSEvgeniy Polyakov static struct attribute *w1_master_default_attrs[] = {
3237785925dSEvgeniy Polyakov 	&w1_master_attribute_name.attr,
3247785925dSEvgeniy Polyakov 	&w1_master_attribute_slaves.attr,
3257785925dSEvgeniy Polyakov 	&w1_master_attribute_slave_count.attr,
3267785925dSEvgeniy Polyakov 	&w1_master_attribute_max_slave_count.attr,
3277785925dSEvgeniy Polyakov 	&w1_master_attribute_attempts.attr,
3287785925dSEvgeniy Polyakov 	&w1_master_attribute_timeout.attr,
3297785925dSEvgeniy Polyakov 	&w1_master_attribute_pointer.attr,
3302a9d0c17SEvgeniy Polyakov 	&w1_master_attribute_search.attr,
3317785925dSEvgeniy Polyakov 	NULL
3321da177e4SLinus Torvalds };
3331da177e4SLinus Torvalds 
3347785925dSEvgeniy Polyakov static struct attribute_group w1_master_defattr_group = {
3357785925dSEvgeniy Polyakov 	.attrs = w1_master_default_attrs,
3361da177e4SLinus Torvalds };
3371da177e4SLinus Torvalds 
3387785925dSEvgeniy Polyakov int w1_create_master_attributes(struct w1_master *master)
3397785925dSEvgeniy Polyakov {
3407785925dSEvgeniy Polyakov 	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
3417785925dSEvgeniy Polyakov }
3427785925dSEvgeniy Polyakov 
3437785925dSEvgeniy Polyakov void w1_destroy_master_attributes(struct w1_master *master)
3447785925dSEvgeniy Polyakov {
3457785925dSEvgeniy Polyakov 	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
3467785925dSEvgeniy Polyakov }
3477785925dSEvgeniy Polyakov 
3487f772ed8SEvgeniy Polyakov #ifdef CONFIG_HOTPLUG
3497f772ed8SEvgeniy Polyakov static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
3507f772ed8SEvgeniy Polyakov {
3517f772ed8SEvgeniy Polyakov 	struct w1_master *md = NULL;
3527f772ed8SEvgeniy Polyakov 	struct w1_slave *sl = NULL;
3537f772ed8SEvgeniy Polyakov 	char *event_owner, *name;
3547f772ed8SEvgeniy Polyakov 	int err, cur_index=0, cur_len=0;
3557f772ed8SEvgeniy Polyakov 
3567f772ed8SEvgeniy Polyakov 	if (dev->driver == &w1_master_driver) {
3577f772ed8SEvgeniy Polyakov 		md = container_of(dev, struct w1_master, dev);
3587f772ed8SEvgeniy Polyakov 		event_owner = "master";
3597f772ed8SEvgeniy Polyakov 		name = md->name;
3607f772ed8SEvgeniy Polyakov 	} else if (dev->driver == &w1_slave_driver) {
3617f772ed8SEvgeniy Polyakov 		sl = container_of(dev, struct w1_slave, dev);
3627f772ed8SEvgeniy Polyakov 		event_owner = "slave";
3637f772ed8SEvgeniy Polyakov 		name = sl->name;
3647f772ed8SEvgeniy Polyakov 	} else {
3657f772ed8SEvgeniy Polyakov 		dev_dbg(dev, "Unknown hotplug event.\n");
3667f772ed8SEvgeniy Polyakov 		return -EINVAL;
3677f772ed8SEvgeniy Polyakov 	}
3687f772ed8SEvgeniy Polyakov 
3697f772ed8SEvgeniy Polyakov 	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", event_owner, name, dev->bus_id);
3707f772ed8SEvgeniy Polyakov 
3717f772ed8SEvgeniy Polyakov 	if (dev->driver != &w1_slave_driver || !sl)
3727f772ed8SEvgeniy Polyakov 		return 0;
3737f772ed8SEvgeniy Polyakov 
3747f772ed8SEvgeniy Polyakov 	err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_FID=%02X", sl->reg_num.family);
3757f772ed8SEvgeniy Polyakov 	if (err)
3767f772ed8SEvgeniy Polyakov 		return err;
3777f772ed8SEvgeniy Polyakov 
3785e8eb850SEvgeniy Polyakov 	err = add_hotplug_env_var(envp, num_envp, &cur_index, buffer, buffer_size, &cur_len, "W1_SLAVE_ID=%024LX", (u64)sl->reg_num.id);
3797f772ed8SEvgeniy Polyakov 	if (err)
3807f772ed8SEvgeniy Polyakov 		return err;
3817f772ed8SEvgeniy Polyakov 
3827f772ed8SEvgeniy Polyakov 	return 0;
3837f772ed8SEvgeniy Polyakov };
3847f772ed8SEvgeniy Polyakov #else
3857f772ed8SEvgeniy Polyakov static int w1_hotplug(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
3867f772ed8SEvgeniy Polyakov {
3877f772ed8SEvgeniy Polyakov 	return 0;
3887f772ed8SEvgeniy Polyakov }
3897f772ed8SEvgeniy Polyakov #endif
3907f772ed8SEvgeniy Polyakov 
3911da177e4SLinus Torvalds static int __w1_attach_slave_device(struct w1_slave *sl)
3921da177e4SLinus Torvalds {
3931da177e4SLinus Torvalds 	int err;
3941da177e4SLinus Torvalds 
3951da177e4SLinus Torvalds 	sl->dev.parent = &sl->master->dev;
3967f772ed8SEvgeniy Polyakov 	sl->dev.driver = &w1_slave_driver;
3971da177e4SLinus Torvalds 	sl->dev.bus = &w1_bus_type;
3981da177e4SLinus Torvalds 	sl->dev.release = &w1_slave_release;
3991da177e4SLinus Torvalds 
4001da177e4SLinus Torvalds 	snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id),
4011da177e4SLinus Torvalds 		 "%02x-%012llx",
4021da177e4SLinus Torvalds 		 (unsigned int) sl->reg_num.family,
4031da177e4SLinus Torvalds 		 (unsigned long long) sl->reg_num.id);
4041da177e4SLinus Torvalds 	snprintf(&sl->name[0], sizeof(sl->name),
4051da177e4SLinus Torvalds 		 "%02x-%012llx",
4061da177e4SLinus Torvalds 		 (unsigned int) sl->reg_num.family,
4071da177e4SLinus Torvalds 		 (unsigned long long) sl->reg_num.id);
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds 	dev_dbg(&sl->dev, "%s: registering %s.\n", __func__,
4101da177e4SLinus Torvalds 		&sl->dev.bus_id[0]);
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds 	err = device_register(&sl->dev);
4131da177e4SLinus Torvalds 	if (err < 0) {
4141da177e4SLinus Torvalds 		dev_err(&sl->dev,
4151da177e4SLinus Torvalds 			"Device registration [%s] failed. err=%d\n",
4161da177e4SLinus Torvalds 			sl->dev.bus_id, err);
4171da177e4SLinus Torvalds 		return err;
4181da177e4SLinus Torvalds 	}
4191da177e4SLinus Torvalds 
420*d2a4ef6aSEvgeniy Polyakov 	/* Create "name" entry */
421*d2a4ef6aSEvgeniy Polyakov 	err = device_create_file(&sl->dev, &w1_slave_attr_name);
4221da177e4SLinus Torvalds 	if (err < 0) {
4231da177e4SLinus Torvalds 		dev_err(&sl->dev,
4241da177e4SLinus Torvalds 			"sysfs file creation for [%s] failed. err=%d\n",
4251da177e4SLinus Torvalds 			sl->dev.bus_id, err);
426*d2a4ef6aSEvgeniy Polyakov 		goto out_unreg;
4271da177e4SLinus Torvalds 	}
4281da177e4SLinus Torvalds 
429*d2a4ef6aSEvgeniy Polyakov 	/* Create "id" entry */
430*d2a4ef6aSEvgeniy Polyakov 	err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
4311da177e4SLinus Torvalds 	if (err < 0) {
4321da177e4SLinus Torvalds 		dev_err(&sl->dev,
4331da177e4SLinus Torvalds 			"sysfs file creation for [%s] failed. err=%d\n",
4341da177e4SLinus Torvalds 			sl->dev.bus_id, err);
435*d2a4ef6aSEvgeniy Polyakov 		goto out_rem1;
4361da177e4SLinus Torvalds 	}
437*d2a4ef6aSEvgeniy Polyakov 
438*d2a4ef6aSEvgeniy Polyakov 	/* if the family driver needs to initialize something... */
439*d2a4ef6aSEvgeniy Polyakov 	if (sl->family->fops && sl->family->fops->add_slave &&
440*d2a4ef6aSEvgeniy Polyakov 	    ((err = sl->family->fops->add_slave(sl)) < 0)) {
441*d2a4ef6aSEvgeniy Polyakov 		dev_err(&sl->dev,
442*d2a4ef6aSEvgeniy Polyakov 			"sysfs file creation for [%s] failed. err=%d\n",
443*d2a4ef6aSEvgeniy Polyakov 			sl->dev.bus_id, err);
444*d2a4ef6aSEvgeniy Polyakov 		goto out_rem2;
44599c5bfe9SEvgeniy Polyakov 	}
4461da177e4SLinus Torvalds 
4471da177e4SLinus Torvalds 	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
4481da177e4SLinus Torvalds 
4491da177e4SLinus Torvalds 	return 0;
450*d2a4ef6aSEvgeniy Polyakov 
451*d2a4ef6aSEvgeniy Polyakov out_rem2:
452*d2a4ef6aSEvgeniy Polyakov 	sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
453*d2a4ef6aSEvgeniy Polyakov out_rem1:
454*d2a4ef6aSEvgeniy Polyakov 	device_remove_file(&sl->dev, &w1_slave_attr_name);
455*d2a4ef6aSEvgeniy Polyakov out_unreg:
456*d2a4ef6aSEvgeniy Polyakov 	device_unregister(&sl->dev);
457*d2a4ef6aSEvgeniy Polyakov 	return err;
4581da177e4SLinus Torvalds }
4591da177e4SLinus Torvalds 
4601da177e4SLinus Torvalds static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
4611da177e4SLinus Torvalds {
4621da177e4SLinus Torvalds 	struct w1_slave *sl;
4631da177e4SLinus Torvalds 	struct w1_family *f;
4641da177e4SLinus Torvalds 	int err;
4651da177e4SLinus Torvalds 	struct w1_netlink_msg msg;
4661da177e4SLinus Torvalds 
4671da177e4SLinus Torvalds 	sl = kmalloc(sizeof(struct w1_slave), GFP_KERNEL);
4681da177e4SLinus Torvalds 	if (!sl) {
4691da177e4SLinus Torvalds 		dev_err(&dev->dev,
4701da177e4SLinus Torvalds 			 "%s: failed to allocate new slave device.\n",
4711da177e4SLinus Torvalds 			 __func__);
4721da177e4SLinus Torvalds 		return -ENOMEM;
4731da177e4SLinus Torvalds 	}
4741da177e4SLinus Torvalds 
4751da177e4SLinus Torvalds 	memset(sl, 0, sizeof(*sl));
4761da177e4SLinus Torvalds 
4771da177e4SLinus Torvalds 	sl->owner = THIS_MODULE;
4781da177e4SLinus Torvalds 	sl->master = dev;
4791da177e4SLinus Torvalds 	set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
4801da177e4SLinus Torvalds 
4811da177e4SLinus Torvalds 	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
4821da177e4SLinus Torvalds 	atomic_set(&sl->refcnt, 0);
4831da177e4SLinus Torvalds 	init_completion(&sl->dev_released);
4841da177e4SLinus Torvalds 
4851da177e4SLinus Torvalds 	spin_lock(&w1_flock);
4861da177e4SLinus Torvalds 	f = w1_family_registered(rn->family);
4871da177e4SLinus Torvalds 	if (!f) {
48899c5bfe9SEvgeniy Polyakov 		f= &w1_default_family;
4891da177e4SLinus Torvalds 		dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
4901da177e4SLinus Torvalds 			  rn->family, rn->family,
4911da177e4SLinus Torvalds 			  (unsigned long long)rn->id, rn->crc);
4921da177e4SLinus Torvalds 	}
4931da177e4SLinus Torvalds 	__w1_family_get(f);
4941da177e4SLinus Torvalds 	spin_unlock(&w1_flock);
4951da177e4SLinus Torvalds 
4961da177e4SLinus Torvalds 	sl->family = f;
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds 
4991da177e4SLinus Torvalds 	err = __w1_attach_slave_device(sl);
5001da177e4SLinus Torvalds 	if (err < 0) {
5011da177e4SLinus Torvalds 		dev_err(&dev->dev, "%s: Attaching %s failed.\n", __func__,
5021da177e4SLinus Torvalds 			 sl->name);
5031da177e4SLinus Torvalds 		w1_family_put(sl->family);
5041da177e4SLinus Torvalds 		kfree(sl);
5051da177e4SLinus Torvalds 		return err;
5061da177e4SLinus Torvalds 	}
5071da177e4SLinus Torvalds 
5081da177e4SLinus Torvalds 	sl->ttl = dev->slave_ttl;
5091da177e4SLinus Torvalds 	dev->slave_count++;
5101da177e4SLinus Torvalds 
5111da177e4SLinus Torvalds 	memcpy(&msg.id.id, rn, sizeof(msg.id.id));
5121da177e4SLinus Torvalds 	msg.type = W1_SLAVE_ADD;
5131da177e4SLinus Torvalds 	w1_netlink_send(dev, &msg);
5141da177e4SLinus Torvalds 
5151da177e4SLinus Torvalds 	return 0;
5161da177e4SLinus Torvalds }
5171da177e4SLinus Torvalds 
5181da177e4SLinus Torvalds static void w1_slave_detach(struct w1_slave *sl)
5191da177e4SLinus Torvalds {
5201da177e4SLinus Torvalds 	struct w1_netlink_msg msg;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 	dev_info(&sl->dev, "%s: detaching %s.\n", __func__, sl->name);
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds 	while (atomic_read(&sl->refcnt)) {
5251da177e4SLinus Torvalds 		printk(KERN_INFO "Waiting for %s to become free: refcnt=%d.\n",
5261da177e4SLinus Torvalds 				sl->name, atomic_read(&sl->refcnt));
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 		if (msleep_interruptible(1000))
5291da177e4SLinus Torvalds 			flush_signals(current);
5301da177e4SLinus Torvalds 	}
5311da177e4SLinus Torvalds 
532*d2a4ef6aSEvgeniy Polyakov 	if (sl->family->fops && sl->family->fops->remove_slave)
533*d2a4ef6aSEvgeniy Polyakov 		sl->family->fops->remove_slave(sl);
534*d2a4ef6aSEvgeniy Polyakov 
535*d2a4ef6aSEvgeniy Polyakov 	sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
536*d2a4ef6aSEvgeniy Polyakov 	device_remove_file(&sl->dev, &w1_slave_attr_name);
5371da177e4SLinus Torvalds 	device_unregister(&sl->dev);
5381da177e4SLinus Torvalds 	w1_family_put(sl->family);
5391da177e4SLinus Torvalds 
5406adf87bdSEvgeniy Polyakov 	sl->master->slave_count--;
5416adf87bdSEvgeniy Polyakov 
5421da177e4SLinus Torvalds 	memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
5431da177e4SLinus Torvalds 	msg.type = W1_SLAVE_REMOVE;
5441da177e4SLinus Torvalds 	w1_netlink_send(sl->master, &msg);
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds 
5471da177e4SLinus Torvalds static struct w1_master *w1_search_master(unsigned long data)
5481da177e4SLinus Torvalds {
5491da177e4SLinus Torvalds 	struct w1_master *dev;
5501da177e4SLinus Torvalds 	int found = 0;
5511da177e4SLinus Torvalds 
5527785925dSEvgeniy Polyakov 	spin_lock_bh(&w1_mlock);
5531da177e4SLinus Torvalds 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
5541da177e4SLinus Torvalds 		if (dev->bus_master->data == data) {
5551da177e4SLinus Torvalds 			found = 1;
5561da177e4SLinus Torvalds 			atomic_inc(&dev->refcnt);
5571da177e4SLinus Torvalds 			break;
5581da177e4SLinus Torvalds 		}
5591da177e4SLinus Torvalds 	}
5607785925dSEvgeniy Polyakov 	spin_unlock_bh(&w1_mlock);
5611da177e4SLinus Torvalds 
5621da177e4SLinus Torvalds 	return (found)?dev:NULL;
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds 
5656adf87bdSEvgeniy Polyakov void w1_reconnect_slaves(struct w1_family *f)
5666adf87bdSEvgeniy Polyakov {
5676adf87bdSEvgeniy Polyakov 	struct w1_master *dev;
5686adf87bdSEvgeniy Polyakov 
5696adf87bdSEvgeniy Polyakov 	spin_lock_bh(&w1_mlock);
5706adf87bdSEvgeniy Polyakov 	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
5716adf87bdSEvgeniy Polyakov 		dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
5726adf87bdSEvgeniy Polyakov 				dev->name, f->fid);
5736adf87bdSEvgeniy Polyakov 		set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
5746adf87bdSEvgeniy Polyakov 	}
5756adf87bdSEvgeniy Polyakov 	spin_unlock_bh(&w1_mlock);
5766adf87bdSEvgeniy Polyakov }
5776adf87bdSEvgeniy Polyakov 
5787785925dSEvgeniy Polyakov static void w1_slave_found(unsigned long data, u64 rn)
5791da177e4SLinus Torvalds {
5801da177e4SLinus Torvalds 	int slave_count;
5811da177e4SLinus Torvalds 	struct w1_slave *sl;
5821da177e4SLinus Torvalds 	struct list_head *ent;
5831da177e4SLinus Torvalds 	struct w1_reg_num *tmp;
5841da177e4SLinus Torvalds 	int family_found = 0;
5851da177e4SLinus Torvalds 	struct w1_master *dev;
5860e65f828SEvgeniy Polyakov 	u64 rn_le = cpu_to_le64(rn);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 	dev = w1_search_master(data);
5891da177e4SLinus Torvalds 	if (!dev) {
5901da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to find w1 master device for data %08lx, it is impossible.\n",
5911da177e4SLinus Torvalds 				data);
5921da177e4SLinus Torvalds 		return;
5931da177e4SLinus Torvalds 	}
5941da177e4SLinus Torvalds 
5951da177e4SLinus Torvalds 	tmp = (struct w1_reg_num *) &rn;
5961da177e4SLinus Torvalds 
5971da177e4SLinus Torvalds 	slave_count = 0;
5981da177e4SLinus Torvalds 	list_for_each(ent, &dev->slist) {
5991da177e4SLinus Torvalds 
6001da177e4SLinus Torvalds 		sl = list_entry(ent, struct w1_slave, w1_slave_entry);
6011da177e4SLinus Torvalds 
6021da177e4SLinus Torvalds 		if (sl->reg_num.family == tmp->family &&
6031da177e4SLinus Torvalds 		    sl->reg_num.id == tmp->id &&
6041da177e4SLinus Torvalds 		    sl->reg_num.crc == tmp->crc) {
6051da177e4SLinus Torvalds 			set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
6061da177e4SLinus Torvalds 			break;
6077785925dSEvgeniy Polyakov 		} else if (sl->reg_num.family == tmp->family) {
6081da177e4SLinus Torvalds 			family_found = 1;
6091da177e4SLinus Torvalds 			break;
6101da177e4SLinus Torvalds 		}
6111da177e4SLinus Torvalds 
6121da177e4SLinus Torvalds 		slave_count++;
6131da177e4SLinus Torvalds 	}
6141da177e4SLinus Torvalds 
6158523ff45Sjohnpol@2ka.mipt.ru 	if (slave_count == dev->slave_count &&
6160e65f828SEvgeniy Polyakov 		rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) {
6178523ff45Sjohnpol@2ka.mipt.ru 		w1_attach_slave_device(dev, tmp);
6181da177e4SLinus Torvalds 	}
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds 	atomic_dec(&dev->refcnt);
6211da177e4SLinus Torvalds }
6221da177e4SLinus Torvalds 
6236b729861SEvgeniy Polyakov /**
6246b729861SEvgeniy Polyakov  * Performs a ROM Search & registers any devices found.
6256b729861SEvgeniy Polyakov  * The 1-wire search is a simple binary tree search.
6266b729861SEvgeniy Polyakov  * For each bit of the address, we read two bits and write one bit.
6276b729861SEvgeniy Polyakov  * The bit written will put to sleep all devies that don't match that bit.
6286b729861SEvgeniy Polyakov  * When the two reads differ, the direction choice is obvious.
6296b729861SEvgeniy Polyakov  * When both bits are 0, we must choose a path to take.
6306b729861SEvgeniy Polyakov  * When we can scan all 64 bits without having to choose a path, we are done.
6316b729861SEvgeniy Polyakov  *
6326b729861SEvgeniy Polyakov  * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com
6336b729861SEvgeniy Polyakov  *
6346b729861SEvgeniy Polyakov  * @dev        The master device to search
6356b729861SEvgeniy Polyakov  * @cb         Function to call when a device is found
6366b729861SEvgeniy Polyakov  */
6376b729861SEvgeniy Polyakov void w1_search(struct w1_master *dev, w1_slave_found_callback cb)
6381da177e4SLinus Torvalds {
6396b729861SEvgeniy Polyakov 	u64 last_rn, rn, tmp64;
6406b729861SEvgeniy Polyakov 	int i, slave_count = 0;
6416b729861SEvgeniy Polyakov 	int last_zero, last_device;
6426b729861SEvgeniy Polyakov 	int search_bit, desc_bit;
6436b729861SEvgeniy Polyakov 	u8  triplet_ret = 0;
6441da177e4SLinus Torvalds 
6456b729861SEvgeniy Polyakov 	search_bit = 0;
6466b729861SEvgeniy Polyakov 	rn = last_rn = 0;
6476b729861SEvgeniy Polyakov 	last_device = 0;
6486b729861SEvgeniy Polyakov 	last_zero = -1;
6491da177e4SLinus Torvalds 
6501da177e4SLinus Torvalds 	desc_bit = 64;
6511da177e4SLinus Torvalds 
6526b729861SEvgeniy Polyakov 	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
6536b729861SEvgeniy Polyakov 		last_rn = rn;
6541da177e4SLinus Torvalds 		rn = 0;
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 		/*
6571da177e4SLinus Torvalds 		 * Reset bus and all 1-wire device state machines
6581da177e4SLinus Torvalds 		 * so they can respond to our requests.
6591da177e4SLinus Torvalds 		 *
6601da177e4SLinus Torvalds 		 * Return 0 - device(s) present, 1 - no devices present.
6611da177e4SLinus Torvalds 		 */
6621da177e4SLinus Torvalds 		if (w1_reset_bus(dev)) {
6632da5bf80SEvgeniy Polyakov 			dev_dbg(&dev->dev, "No devices present on the wire.\n");
6641da177e4SLinus Torvalds 			break;
6651da177e4SLinus Torvalds 		}
6661da177e4SLinus Torvalds 
6676b729861SEvgeniy Polyakov 		/* Start the search */
6681da177e4SLinus Torvalds 		w1_write_8(dev, W1_SEARCH);
6691da177e4SLinus Torvalds 		for (i = 0; i < 64; ++i) {
6706b729861SEvgeniy Polyakov 			/* Determine the direction/search bit */
6716b729861SEvgeniy Polyakov 			if (i == desc_bit)
6726b729861SEvgeniy Polyakov 				search_bit = 1;	  /* took the 0 path last time, so take the 1 path */
6736b729861SEvgeniy Polyakov 			else if (i > desc_bit)
6746b729861SEvgeniy Polyakov 				search_bit = 0;	  /* take the 0 path on the next branch */
6756b729861SEvgeniy Polyakov 			else
6766b729861SEvgeniy Polyakov 				search_bit = ((last_rn >> i) & 0x1);
6771da177e4SLinus Torvalds 
6786b729861SEvgeniy Polyakov 			/** Read two bits and write one bit */
6796b729861SEvgeniy Polyakov 			triplet_ret = w1_triplet(dev, search_bit);
6806b729861SEvgeniy Polyakov 
6816b729861SEvgeniy Polyakov 			/* quit if no device responded */
6826b729861SEvgeniy Polyakov 			if ( (triplet_ret & 0x03) == 0x03 )
6831da177e4SLinus Torvalds 				break;
6841da177e4SLinus Torvalds 
6856b729861SEvgeniy Polyakov 			/* If both directions were valid, and we took the 0 path... */
6866b729861SEvgeniy Polyakov 			if (triplet_ret == 0)
6871da177e4SLinus Torvalds 				last_zero = i;
6886b729861SEvgeniy Polyakov 
6896b729861SEvgeniy Polyakov 			/* extract the direction taken & update the device number */
6906b729861SEvgeniy Polyakov 			tmp64 = (triplet_ret >> 2);
6916b729861SEvgeniy Polyakov 			rn |= (tmp64 << i);
6921da177e4SLinus Torvalds 		}
6931da177e4SLinus Torvalds 
6946b729861SEvgeniy Polyakov 		if ( (triplet_ret & 0x03) != 0x03 ) {
6956b729861SEvgeniy Polyakov 			if ( (desc_bit == last_zero) || (last_zero < 0))
6961da177e4SLinus Torvalds 				last_device = 1;
6971da177e4SLinus Torvalds 			desc_bit = last_zero;
6986b729861SEvgeniy Polyakov 			cb(dev->bus_master->data, rn);
6996b729861SEvgeniy Polyakov 		}
7001da177e4SLinus Torvalds 	}
7011da177e4SLinus Torvalds }
7021da177e4SLinus Torvalds 
7037785925dSEvgeniy Polyakov static int w1_control(void *data)
7041da177e4SLinus Torvalds {
7057785925dSEvgeniy Polyakov 	struct w1_slave *sl, *sln;
7067785925dSEvgeniy Polyakov 	struct w1_master *dev, *n;
7071da177e4SLinus Torvalds 	int err, have_to_wait = 0;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 	daemonize("w1_control");
7101da177e4SLinus Torvalds 	allow_signal(SIGTERM);
7111da177e4SLinus Torvalds 
7121da177e4SLinus Torvalds 	while (!control_needs_exit || have_to_wait) {
7131da177e4SLinus Torvalds 		have_to_wait = 0;
7141da177e4SLinus Torvalds 
7153e1d1d28SChristoph Lameter 		try_to_freeze();
7161da177e4SLinus Torvalds 		msleep_interruptible(w1_timeout * 1000);
7171da177e4SLinus Torvalds 
7181da177e4SLinus Torvalds 		if (signal_pending(current))
7191da177e4SLinus Torvalds 			flush_signals(current);
7201da177e4SLinus Torvalds 
7217785925dSEvgeniy Polyakov 		list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
7226adf87bdSEvgeniy Polyakov 			if (!control_needs_exit && !dev->flags)
7231da177e4SLinus Torvalds 				continue;
7241da177e4SLinus Torvalds 			/*
7251da177e4SLinus Torvalds 			 * Little race: we can create thread but not set the flag.
7261da177e4SLinus Torvalds 			 * Get a chance for external process to set flag up.
7271da177e4SLinus Torvalds 			 */
7281da177e4SLinus Torvalds 			if (!dev->initialized) {
7291da177e4SLinus Torvalds 				have_to_wait = 1;
7301da177e4SLinus Torvalds 				continue;
7311da177e4SLinus Torvalds 			}
7321da177e4SLinus Torvalds 
7331da177e4SLinus Torvalds 			if (control_needs_exit) {
7346adf87bdSEvgeniy Polyakov 				set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
7351da177e4SLinus Torvalds 
7361da177e4SLinus Torvalds 				err = kill_proc(dev->kpid, SIGTERM, 1);
7371da177e4SLinus Torvalds 				if (err)
7381da177e4SLinus Torvalds 					dev_err(&dev->dev,
7391da177e4SLinus Torvalds 						 "Failed to send signal to w1 kernel thread %d.\n",
7401da177e4SLinus Torvalds 						 dev->kpid);
7411da177e4SLinus Torvalds 			}
7421da177e4SLinus Torvalds 
7436adf87bdSEvgeniy Polyakov 			if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
7441da177e4SLinus Torvalds 				wait_for_completion(&dev->dev_exited);
7456adf87bdSEvgeniy Polyakov 				spin_lock_bh(&w1_mlock);
7466adf87bdSEvgeniy Polyakov 				list_del(&dev->w1_master_entry);
7476adf87bdSEvgeniy Polyakov 				spin_unlock_bh(&w1_mlock);
7481da177e4SLinus Torvalds 
7497785925dSEvgeniy Polyakov 				list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
7501da177e4SLinus Torvalds 					list_del(&sl->w1_slave_entry);
7511da177e4SLinus Torvalds 
7521da177e4SLinus Torvalds 					w1_slave_detach(sl);
7531da177e4SLinus Torvalds 					kfree(sl);
7541da177e4SLinus Torvalds 				}
7551da177e4SLinus Torvalds 				w1_destroy_master_attributes(dev);
7561da177e4SLinus Torvalds 				atomic_dec(&dev->refcnt);
7576adf87bdSEvgeniy Polyakov 				continue;
7586adf87bdSEvgeniy Polyakov 			}
7596adf87bdSEvgeniy Polyakov 
7606adf87bdSEvgeniy Polyakov 			if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
7616adf87bdSEvgeniy Polyakov 				dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
7626adf87bdSEvgeniy Polyakov 				down(&dev->mutex);
7636adf87bdSEvgeniy Polyakov 				list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
7646adf87bdSEvgeniy Polyakov 					if (sl->family->fid == W1_FAMILY_DEFAULT) {
7656adf87bdSEvgeniy Polyakov 						struct w1_reg_num rn;
7666adf87bdSEvgeniy Polyakov 						list_del(&sl->w1_slave_entry);
7676adf87bdSEvgeniy Polyakov 						w1_slave_detach(sl);
7686adf87bdSEvgeniy Polyakov 
7696adf87bdSEvgeniy Polyakov 						memcpy(&rn, &sl->reg_num, sizeof(rn));
7706adf87bdSEvgeniy Polyakov 
7716adf87bdSEvgeniy Polyakov 						kfree(sl);
7726adf87bdSEvgeniy Polyakov 
7736adf87bdSEvgeniy Polyakov 						w1_attach_slave_device(dev, &rn);
7746adf87bdSEvgeniy Polyakov 					}
7756adf87bdSEvgeniy Polyakov 				}
7766adf87bdSEvgeniy Polyakov 				clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
7776adf87bdSEvgeniy Polyakov 				up(&dev->mutex);
7786adf87bdSEvgeniy Polyakov 			}
7791da177e4SLinus Torvalds 		}
7801da177e4SLinus Torvalds 	}
7811da177e4SLinus Torvalds 
7821da177e4SLinus Torvalds 	complete_and_exit(&w1_control_complete, 0);
7831da177e4SLinus Torvalds }
7841da177e4SLinus Torvalds 
7851da177e4SLinus Torvalds int w1_process(void *data)
7861da177e4SLinus Torvalds {
7871da177e4SLinus Torvalds 	struct w1_master *dev = (struct w1_master *) data;
7887785925dSEvgeniy Polyakov 	struct w1_slave *sl, *sln;
7891da177e4SLinus Torvalds 
7901da177e4SLinus Torvalds 	daemonize("%s", dev->name);
7911da177e4SLinus Torvalds 	allow_signal(SIGTERM);
7921da177e4SLinus Torvalds 
7936adf87bdSEvgeniy Polyakov 	while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
7943e1d1d28SChristoph Lameter 		try_to_freeze();
7951da177e4SLinus Torvalds 		msleep_interruptible(w1_timeout * 1000);
7961da177e4SLinus Torvalds 
7971da177e4SLinus Torvalds 		if (signal_pending(current))
7981da177e4SLinus Torvalds 			flush_signals(current);
7991da177e4SLinus Torvalds 
8006adf87bdSEvgeniy Polyakov 		if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags))
8011da177e4SLinus Torvalds 			break;
8021da177e4SLinus Torvalds 
8031da177e4SLinus Torvalds 		if (!dev->initialized)
8041da177e4SLinus Torvalds 			continue;
8051da177e4SLinus Torvalds 
8062a9d0c17SEvgeniy Polyakov 		if (dev->search_count == 0)
8072a9d0c17SEvgeniy Polyakov 			continue;
8082a9d0c17SEvgeniy Polyakov 
8091da177e4SLinus Torvalds 		if (down_interruptible(&dev->mutex))
8101da177e4SLinus Torvalds 			continue;
8111da177e4SLinus Torvalds 
8127785925dSEvgeniy Polyakov 		list_for_each_entry(sl, &dev->slist, w1_slave_entry)
8131da177e4SLinus Torvalds 			clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 		w1_search_devices(dev, w1_slave_found);
8161da177e4SLinus Torvalds 
8177785925dSEvgeniy Polyakov 		list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
8187785925dSEvgeniy Polyakov 			if (!test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags) && !--sl->ttl) {
8191da177e4SLinus Torvalds 				list_del (&sl->w1_slave_entry);
8201da177e4SLinus Torvalds 
8211da177e4SLinus Torvalds 				w1_slave_detach(sl);
8221da177e4SLinus Torvalds 				kfree(sl);
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 				dev->slave_count--;
8257785925dSEvgeniy Polyakov 			} else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
8261da177e4SLinus Torvalds 				sl->ttl = dev->slave_ttl;
8271da177e4SLinus Torvalds 		}
8282a9d0c17SEvgeniy Polyakov 
8292a9d0c17SEvgeniy Polyakov 		if (dev->search_count > 0)
8302a9d0c17SEvgeniy Polyakov 			dev->search_count--;
8312a9d0c17SEvgeniy Polyakov 
8321da177e4SLinus Torvalds 		up(&dev->mutex);
8331da177e4SLinus Torvalds 	}
8341da177e4SLinus Torvalds 
8351da177e4SLinus Torvalds 	atomic_dec(&dev->refcnt);
8361da177e4SLinus Torvalds 	complete_and_exit(&dev->dev_exited, 0);
8371da177e4SLinus Torvalds 
8381da177e4SLinus Torvalds 	return 0;
8391da177e4SLinus Torvalds }
8401da177e4SLinus Torvalds 
8417785925dSEvgeniy Polyakov static int w1_init(void)
8421da177e4SLinus Torvalds {
8431da177e4SLinus Torvalds 	int retval;
8441da177e4SLinus Torvalds 
8451da177e4SLinus Torvalds 	printk(KERN_INFO "Driver for 1-wire Dallas network protocol.\n");
8461da177e4SLinus Torvalds 
8471da177e4SLinus Torvalds 	retval = bus_register(&w1_bus_type);
8481da177e4SLinus Torvalds 	if (retval) {
8491da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to register bus. err=%d.\n", retval);
8501da177e4SLinus Torvalds 		goto err_out_exit_init;
8511da177e4SLinus Torvalds 	}
8521da177e4SLinus Torvalds 
8537f772ed8SEvgeniy Polyakov 	retval = driver_register(&w1_master_driver);
8541da177e4SLinus Torvalds 	if (retval) {
8551da177e4SLinus Torvalds 		printk(KERN_ERR
8561da177e4SLinus Torvalds 			"Failed to register master driver. err=%d.\n",
8571da177e4SLinus Torvalds 			retval);
8581da177e4SLinus Torvalds 		goto err_out_bus_unregister;
8591da177e4SLinus Torvalds 	}
8601da177e4SLinus Torvalds 
8617f772ed8SEvgeniy Polyakov 	retval = driver_register(&w1_slave_driver);
8627f772ed8SEvgeniy Polyakov 	if (retval) {
8637f772ed8SEvgeniy Polyakov 		printk(KERN_ERR
8647f772ed8SEvgeniy Polyakov 			"Failed to register master driver. err=%d.\n",
8657f772ed8SEvgeniy Polyakov 			retval);
8667f772ed8SEvgeniy Polyakov 		goto err_out_master_unregister;
8677f772ed8SEvgeniy Polyakov 	}
8687f772ed8SEvgeniy Polyakov 
8691da177e4SLinus Torvalds 	control_thread = kernel_thread(&w1_control, NULL, 0);
8701da177e4SLinus Torvalds 	if (control_thread < 0) {
8711da177e4SLinus Torvalds 		printk(KERN_ERR "Failed to create control thread. err=%d\n",
8721da177e4SLinus Torvalds 			control_thread);
8731da177e4SLinus Torvalds 		retval = control_thread;
8747f772ed8SEvgeniy Polyakov 		goto err_out_slave_unregister;
8751da177e4SLinus Torvalds 	}
8761da177e4SLinus Torvalds 
8771da177e4SLinus Torvalds 	return 0;
8781da177e4SLinus Torvalds 
8797f772ed8SEvgeniy Polyakov err_out_slave_unregister:
8807f772ed8SEvgeniy Polyakov 	driver_unregister(&w1_slave_driver);
8817f772ed8SEvgeniy Polyakov 
8827f772ed8SEvgeniy Polyakov err_out_master_unregister:
8837f772ed8SEvgeniy Polyakov 	driver_unregister(&w1_master_driver);
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds err_out_bus_unregister:
8861da177e4SLinus Torvalds 	bus_unregister(&w1_bus_type);
8871da177e4SLinus Torvalds 
8881da177e4SLinus Torvalds err_out_exit_init:
8891da177e4SLinus Torvalds 	return retval;
8901da177e4SLinus Torvalds }
8911da177e4SLinus Torvalds 
8927785925dSEvgeniy Polyakov static void w1_fini(void)
8931da177e4SLinus Torvalds {
8941da177e4SLinus Torvalds 	struct w1_master *dev;
8951da177e4SLinus Torvalds 
8967785925dSEvgeniy Polyakov 	list_for_each_entry(dev, &w1_masters, w1_master_entry)
8971da177e4SLinus Torvalds 		__w1_remove_master_device(dev);
8981da177e4SLinus Torvalds 
8991da177e4SLinus Torvalds 	control_needs_exit = 1;
9001da177e4SLinus Torvalds 	wait_for_completion(&w1_control_complete);
9011da177e4SLinus Torvalds 
9027f772ed8SEvgeniy Polyakov 	driver_unregister(&w1_slave_driver);
9037f772ed8SEvgeniy Polyakov 	driver_unregister(&w1_master_driver);
9041da177e4SLinus Torvalds 	bus_unregister(&w1_bus_type);
9051da177e4SLinus Torvalds }
9061da177e4SLinus Torvalds 
9071da177e4SLinus Torvalds module_init(w1_init);
9081da177e4SLinus Torvalds module_exit(w1_fini);
909