[PATCH] w1: reconnect feature.
authorEvgeniy Polyakov <johnpol@2ka.mipt.ru>
Fri, 3 Jun 2005 21:29:25 +0000 (01:29 +0400)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 22 Jun 2005 04:43:12 +0000 (21:43 -0700)
I've created reconnect feature - if on start there are no registered families
all new devices will have defailt family, later when driver for appropriate
family is loaded, slaves, which were faound earlier, will still have defult
family instead of right one. Reconnect feature will force control thread to run
through all master devices and all slaves found and search for slaves with
default family id and try to reconnect them.

It does not store newly registered family and does not check only those slaves
which have reg_num.family the same as being registered one - all slaves with
default family are reconnected.

Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/w1/ds_w1_bridge.c
drivers/w1/w1.c
drivers/w1/w1.h
drivers/w1/w1_family.c
drivers/w1/w1_int.c

index 0baaeb5fd630e134f33f75e7ed1247fd9132224d..7bddd8ac7d7f7a615c3fe5e71b1078e244875719 100644 (file)
@@ -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)
index 0e6ccd46af0e37508fdaf989a8f9177e4630c84e..b460927ec32ad78432660372a7fa20ab49dedfef 100644 (file)
@@ -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)
index 6b5f7be50b8ac2f6c8da6cae765c83c7422a416e..4f0a986e33e3f6332a688c35c1c2923ac1530ccd 100644 (file)
@@ -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;
 
index b8502d910c507be2ff1e02e1aac0d42e70eec452..73e73f6be48ac75bd0e27036c61427ba7808da3a 100644 (file)
@@ -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;
 }
 
index cf18f1324f03491112d7838c1a443e132bcf35ac..35e85d961702cb92664c65b0261f53199d5f4b9f 100644 (file)
@@ -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,