static int control_needs_exit;
static DECLARE_COMPLETION(w1_control_complete);
+/* stuff for the default family */
+static ssize_t w1_famdefault_read_name(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct w1_slave *sl = container_of(dev, struct w1_slave, dev);
+ return(sprintf(buf, "%s\n", sl->name));
+}
+static struct w1_family_ops w1_default_fops = {
+ .rname = &w1_famdefault_read_name,
+};
+static struct w1_family w1_default_family = {
+ .fops = &w1_default_fops,
+};
+
static int w1_master_match(struct device *dev, struct device_driver *drv)
{
return 1;
return count;
}
+static ssize_t w1_master_attribute_store_search(struct device * dev,
+ struct device_attribute *attr,
+ const char * buf, size_t count)
+{
+ struct w1_master *md = container_of(dev, struct w1_master, dev);
+
+ if (down_interruptible (&md->mutex))
+ return -EBUSY;
+
+ md->search_count = simple_strtol(buf, NULL, 0);
+
+ up(&md->mutex);
+
+ return count;
+}
+
+static ssize_t w1_master_attribute_show_search(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct w1_master *md = container_of(dev, struct w1_master, dev);
+ ssize_t count;
+
+ if (down_interruptible (&md->mutex))
+ return -EBUSY;
+
+ count = sprintf(buf, "%d\n", md->search_count);
+
+ up(&md->mutex);
+
+ return count;
+}
+
static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w1_master *md = container_of(dev, struct w1_master, dev);
__ATTR(w1_master_##_name, _mode, \
w1_master_attribute_show_##_name, NULL)
+#define W1_MASTER_ATTR_RW(_name, _mode) \
+ struct device_attribute w1_master_attribute_##_name = \
+ __ATTR(w1_master_##_name, _mode, \
+ w1_master_attribute_show_##_name, \
+ w1_master_attribute_store_##_name)
+
static W1_MASTER_ATTR_RO(name, S_IRUGO);
static W1_MASTER_ATTR_RO(slaves, S_IRUGO);
static W1_MASTER_ATTR_RO(slave_count, S_IRUGO);
static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
+static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
&w1_master_attribute_attempts.attr,
&w1_master_attribute_timeout.attr,
&w1_master_attribute_pointer.attr,
+ &w1_master_attribute_search.attr,
NULL
};
return err;
}
- err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
- if (err < 0) {
- dev_err(&sl->dev,
- "sysfs file creation for [%s] failed. err=%d\n",
- sl->dev.bus_id, err);
- device_remove_file(&sl->dev, &sl->attr_name);
- device_unregister(&sl->dev);
- return err;
+ if ( sl->attr_bin.read ) {
+ err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin);
+ if (err < 0) {
+ dev_err(&sl->dev,
+ "sysfs file creation for [%s] failed. err=%d\n",
+ sl->dev.bus_id, err);
+ device_remove_file(&sl->dev, &sl->attr_name);
+ device_unregister(&sl->dev);
+ return err;
+ }
}
list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
spin_lock(&w1_flock);
f = w1_family_registered(rn->family);
if (!f) {
- spin_unlock(&w1_flock);
+ f= &w1_default_family;
dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered.\n",
rn->family, rn->family,
(unsigned long long)rn->id, rn->crc);
- kfree(sl);
- return -ENODEV;
}
__w1_family_get(f);
spin_unlock(&w1_flock);
flush_signals(current);
}
- sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
+ if ( sl->attr_bin.read ) {
+ sysfs_remove_bin_file (&sl->dev.kobj, &sl->attr_bin);
+ }
device_remove_file(&sl->dev, &sl->attr_name);
device_unregister(&sl->dev);
w1_family_put(sl->family);
+ sl->master->slave_count--;
+
memcpy(&msg.id.id, &sl->reg_num, sizeof(msg.id.id));
msg.type = W1_SLAVE_REMOVE;
w1_netlink_send(sl->master, &msg);
return (found)?dev:NULL;
}
+void w1_reconnect_slaves(struct w1_family *f)
+{
+ struct w1_master *dev;
+
+ spin_lock_bh(&w1_mlock);
+ list_for_each_entry(dev, &w1_masters, w1_master_entry) {
+ dev_info(&dev->dev, "Reconnecting slaves in %s into new family %02x.\n",
+ dev->name, f->fid);
+ set_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
+ }
+ spin_unlock_bh(&w1_mlock);
+}
+
+
static void w1_slave_found(unsigned long data, u64 rn)
{
int slave_count;
while (!control_needs_exit || have_to_wait) {
have_to_wait = 0;
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
msleep_interruptible(w1_timeout * 1000);
if (signal_pending(current))
flush_signals(current);
list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
- if (!control_needs_exit && !dev->need_exit)
+ if (!control_needs_exit && !dev->flags)
continue;
/*
* Little race: we can create thread but not set the flag.
continue;
}
- spin_lock_bh(&w1_mlock);
- list_del(&dev->w1_master_entry);
- spin_unlock_bh(&w1_mlock);
-
if (control_needs_exit) {
- dev->need_exit = 1;
+ set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
err = kill_proc(dev->kpid, SIGTERM, 1);
if (err)
dev->kpid);
}
- wait_for_completion(&dev->dev_exited);
+ if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
+ wait_for_completion(&dev->dev_exited);
+ spin_lock_bh(&w1_mlock);
+ list_del(&dev->w1_master_entry);
+ spin_unlock_bh(&w1_mlock);
+
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+ list_del(&sl->w1_slave_entry);
+
+ w1_slave_detach(sl);
+ kfree(sl);
+ }
+ w1_destroy_master_attributes(dev);
+ atomic_dec(&dev->refcnt);
+ continue;
+ }
+
+ if (test_bit(W1_MASTER_NEED_RECONNECT, &dev->flags)) {
+ dev_info(&dev->dev, "Reconnecting slaves in device %s.\n", dev->name);
+ down(&dev->mutex);
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+ if (sl->family->fid == W1_FAMILY_DEFAULT) {
+ struct w1_reg_num rn;
+ list_del(&sl->w1_slave_entry);
+ w1_slave_detach(sl);
+
+ memcpy(&rn, &sl->reg_num, sizeof(rn));
- list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
- list_del(&sl->w1_slave_entry);
+ kfree(sl);
- w1_slave_detach(sl);
- kfree(sl);
+ w1_attach_slave_device(dev, &rn);
+ }
+ }
+ clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
+ up(&dev->mutex);
}
- w1_destroy_master_attributes(dev);
- atomic_dec(&dev->refcnt);
}
}
daemonize("%s", dev->name);
allow_signal(SIGTERM);
- while (!dev->need_exit) {
- try_to_freeze(PF_FREEZE);
+ while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
+ try_to_freeze();
msleep_interruptible(w1_timeout * 1000);
if (signal_pending(current))
flush_signals(current);
- if (dev->need_exit)
+ if (test_bit(W1_MASTER_NEED_EXIT, &dev->flags))
break;
if (!dev->initialized)
continue;
+ if (dev->search_count == 0)
+ continue;
+
if (down_interruptible(&dev->mutex))
continue;
list_for_each_entry(sl, &dev->slist, w1_slave_entry)
- clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+ clear_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
w1_search_devices(dev, w1_slave_found);
} else if (test_bit(W1_SLAVE_ACTIVE, (unsigned long *)&sl->flags))
sl->ttl = dev->slave_ttl;
}
+
+ if (dev->search_count > 0)
+ dev->search_count--;
+
up(&dev->mutex);
}