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