summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/w1/ds_w1_bridge.c4
-rw-r--r--drivers/w1/w1.c68
-rw-r--r--drivers/w1/w1.h6
-rw-r--r--drivers/w1/w1_family.c3
-rw-r--r--drivers/w1/w1_int.c11
5 files changed, 67 insertions, 25 deletions
diff --git a/drivers/w1/ds_w1_bridge.c b/drivers/w1/ds_w1_bridge.c
index 0baaeb5fd630..7bddd8ac7d7f 100644
--- a/drivers/w1/ds_w1_bridge.c
+++ b/drivers/w1/ds_w1_bridge.c
@@ -83,11 +83,11 @@ static u8 ds9490r_read_byte(unsigned long data)
 	return byte;
 }
 
-static void ds9490r_write_block(unsigned long data, u8 *buf, int len)
+static void ds9490r_write_block(unsigned long data, const u8 *buf, int len)
 {
 	struct ds_device *dev = (struct ds_device *)data;
 
-	ds_write_block(dev, buf, len);
+	ds_write_block(dev, (u8 *)buf, len);
 }
 
 static u8 ds9490r_read_block(unsigned long data, u8 *buf, int len)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 0e6ccd46af0e..b460927ec32a 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -469,6 +469,8 @@ static void w1_slave_detach(struct w1_slave *sl)
 	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);
@@ -492,6 +494,20 @@ static struct w1_master *w1_search_master(unsigned long data)
 	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;
@@ -637,7 +653,7 @@ static int w1_control(void *data)
 			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.
@@ -648,12 +664,8 @@ static int w1_control(void *data)
 				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)
@@ -662,16 +674,42 @@ static int w1_control(void *data)
 						 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);
 		}
 	}
 
@@ -686,14 +724,14 @@ int w1_process(void *data)
 	daemonize("%s", dev->name);
 	allow_signal(SIGTERM);
 
-	while (!dev->need_exit) {
+	while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
 		try_to_freeze(PF_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)
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 6b5f7be50b8a..4f0a986e33e3 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -151,6 +151,9 @@ struct w1_bus_master
 	void		(*search)(unsigned long, w1_slave_found_callback);
 };
 
+#define W1_MASTER_NEED_EXIT		0
+#define W1_MASTER_NEED_RECONNECT	1
+
 struct w1_master
 {
 	struct list_head	w1_master_entry;
@@ -169,7 +172,8 @@ struct w1_master
 	void			*priv;
 	int			priv_size;
 
-	int			need_exit;
+	long			flags;
+
 	pid_t			kpid;
 	struct semaphore	mutex;
 
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index b8502d910c50..73e73f6be48a 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -60,9 +60,10 @@ int w1_register_family(struct w1_family *newf)
 		newf->need_exit = 0;
 		list_add_tail(&newf->family_entry, &w1_families);
 	}
-
 	spin_unlock(&w1_flock);
 
+	w1_reconnect_slaves(newf);
+
 	return ret;
 }
 
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index cf18f1324f03..35e85d961702 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -124,10 +124,9 @@ int w1_add_master_device(struct w1_bus_master *master)
 
         /* validate minimum functionality */
         if (!(master->touch_bit && master->reset_bus) &&
-            !(master->write_bit && master->read_bit))
-        {
-           printk(KERN_ERR "w1_add_master_device: invalid function set\n");
-           return(-EINVAL);
+            !(master->write_bit && master->read_bit)) {
+		printk(KERN_ERR "w1_add_master_device: invalid function set\n");
+		return(-EINVAL);
         }
 
 	dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_driver, &w1_device);
@@ -163,7 +162,7 @@ int w1_add_master_device(struct w1_bus_master *master)
 	return 0;
 
 err_out_kill_thread:
-	dev->need_exit = 1;
+	set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
 	if (kill_proc(dev->kpid, SIGTERM, 1))
 		dev_err(&dev->dev,
 			 "Failed to send signal to w1 kernel thread %d.\n",
@@ -181,7 +180,7 @@ void __w1_remove_master_device(struct w1_master *dev)
 	int err;
 	struct w1_netlink_msg msg;
 
-	dev->need_exit = 1;
+	set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
 	err = kill_proc(dev->kpid, SIGTERM, 1);
 	if (err)
 		dev_err(&dev->dev,