aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/w1/w1_int.c')
-rw-r--r--drivers/w1/w1_int.c88
1 files changed, 72 insertions, 16 deletions
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index 6840dfebe4d4..a3a54567bfba 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -29,7 +29,11 @@
29#include "w1_netlink.h" 29#include "w1_netlink.h"
30#include "w1_int.h" 30#include "w1_int.h"
31 31
32static u32 w1_ids = 1; 32static int w1_search_count = -1; /* Default is continual scan */
33module_param_named(search_count, w1_search_count, int, 0);
34
35static int w1_enable_pullup = 1;
36module_param_named(enable_pullup, w1_enable_pullup, int, 0);
33 37
34static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, 38static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
35 struct device_driver *driver, 39 struct device_driver *driver,
@@ -59,8 +63,12 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
59 dev->initialized = 0; 63 dev->initialized = 0;
60 dev->id = id; 64 dev->id = id;
61 dev->slave_ttl = slave_ttl; 65 dev->slave_ttl = slave_ttl;
62 dev->search_count = -1; /* continual scan */ 66 dev->search_count = w1_search_count;
67 dev->enable_pullup = w1_enable_pullup;
63 68
69 /* 1 for w1_process to decrement
70 * 1 for __w1_remove_master_device to decrement
71 */
64 atomic_set(&dev->refcnt, 2); 72 atomic_set(&dev->refcnt, 2);
65 73
66 INIT_LIST_HEAD(&dev->slist); 74 INIT_LIST_HEAD(&dev->slist);
@@ -93,9 +101,10 @@ static void w1_free_dev(struct w1_master *dev)
93 101
94int w1_add_master_device(struct w1_bus_master *master) 102int w1_add_master_device(struct w1_bus_master *master)
95{ 103{
96 struct w1_master *dev; 104 struct w1_master *dev, *entry;
97 int retval = 0; 105 int retval = 0;
98 struct w1_netlink_msg msg; 106 struct w1_netlink_msg msg;
107 int id, found;
99 108
100 /* validate minimum functionality */ 109 /* validate minimum functionality */
101 if (!(master->touch_bit && master->reset_bus) && 110 if (!(master->touch_bit && master->reset_bus) &&
@@ -104,10 +113,50 @@ int w1_add_master_device(struct w1_bus_master *master)
104 printk(KERN_ERR "w1_add_master_device: invalid function set\n"); 113 printk(KERN_ERR "w1_add_master_device: invalid function set\n");
105 return(-EINVAL); 114 return(-EINVAL);
106 } 115 }
116 /* While it would be electrically possible to make a device that
117 * generated a strong pullup in bit bang mode, only hardare that
118 * controls 1-wire time frames are even expected to support a strong
119 * pullup. w1_io.c would need to support calling set_pullup before
120 * the last write_bit operation of a w1_write_8 which it currently
121 * doesn't.
122 */
123 if (!master->write_byte && !master->touch_bit && master->set_pullup) {
124 printk(KERN_ERR "w1_add_master_device: set_pullup requires "
125 "write_byte or touch_bit, disabling\n");
126 master->set_pullup = NULL;
127 }
128
129 /* Lock until the device is added (or not) to w1_masters. */
130 mutex_lock(&w1_mlock);
131 /* Search for the first available id (starting at 1). */
132 id = 0;
133 do {
134 ++id;
135 found = 0;
136 list_for_each_entry(entry, &w1_masters, w1_master_entry) {
137 if (entry->id == id) {
138 found = 1;
139 break;
140 }
141 }
142 } while (found);
107 143
108 dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device); 144 dev = w1_alloc_dev(id, w1_max_slave_count, w1_max_slave_ttl,
109 if (!dev) 145 &w1_master_driver, &w1_master_device);
146 if (!dev) {
147 mutex_unlock(&w1_mlock);
110 return -ENOMEM; 148 return -ENOMEM;
149 }
150
151 retval = w1_create_master_attributes(dev);
152 if (retval) {
153 mutex_unlock(&w1_mlock);
154 goto err_out_free_dev;
155 }
156
157 memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
158
159 dev->initialized = 1;
111 160
112 dev->thread = kthread_run(&w1_process, dev, "%s", dev->name); 161 dev->thread = kthread_run(&w1_process, dev, "%s", dev->name);
113 if (IS_ERR(dev->thread)) { 162 if (IS_ERR(dev->thread)) {
@@ -115,18 +164,10 @@ int w1_add_master_device(struct w1_bus_master *master)
115 dev_err(&dev->dev, 164 dev_err(&dev->dev,
116 "Failed to create new kernel thread. err=%d\n", 165 "Failed to create new kernel thread. err=%d\n",
117 retval); 166 retval);
118 goto err_out_free_dev; 167 mutex_unlock(&w1_mlock);
168 goto err_out_rm_attr;
119 } 169 }
120 170
121 retval = w1_create_master_attributes(dev);
122 if (retval)
123 goto err_out_kill_thread;
124
125 memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
126
127 dev->initialized = 1;
128
129 mutex_lock(&w1_mlock);
130 list_add(&dev->w1_master_entry, &w1_masters); 171 list_add(&dev->w1_master_entry, &w1_masters);
131 mutex_unlock(&w1_mlock); 172 mutex_unlock(&w1_mlock);
132 173
@@ -137,8 +178,12 @@ int w1_add_master_device(struct w1_bus_master *master)
137 178
138 return 0; 179 return 0;
139 180
181#if 0 /* Thread cleanup code, not required currently. */
140err_out_kill_thread: 182err_out_kill_thread:
141 kthread_stop(dev->thread); 183 kthread_stop(dev->thread);
184#endif
185err_out_rm_attr:
186 w1_destroy_master_attributes(dev);
142err_out_free_dev: 187err_out_free_dev:
143 w1_free_dev(dev); 188 w1_free_dev(dev);
144 189
@@ -148,10 +193,21 @@ err_out_free_dev:
148void __w1_remove_master_device(struct w1_master *dev) 193void __w1_remove_master_device(struct w1_master *dev)
149{ 194{
150 struct w1_netlink_msg msg; 195 struct w1_netlink_msg msg;
196 struct w1_slave *sl, *sln;
151 197
152 set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
153 kthread_stop(dev->thread); 198 kthread_stop(dev->thread);
154 199
200 mutex_lock(&w1_mlock);
201 list_del(&dev->w1_master_entry);
202 mutex_unlock(&w1_mlock);
203
204 mutex_lock(&dev->mutex);
205 list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry)
206 w1_slave_detach(sl);
207 w1_destroy_master_attributes(dev);
208 mutex_unlock(&dev->mutex);
209 atomic_dec(&dev->refcnt);
210
155 while (atomic_read(&dev->refcnt)) { 211 while (atomic_read(&dev->refcnt)) {
156 dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n", 212 dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
157 dev->name, atomic_read(&dev->refcnt)); 213 dev->name, atomic_read(&dev->refcnt));