diff options
Diffstat (limited to 'drivers/w1/w1_int.c')
-rw-r--r-- | drivers/w1/w1_int.c | 88 |
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 | ||
32 | static u32 w1_ids = 1; | 32 | static int w1_search_count = -1; /* Default is continual scan */ |
33 | module_param_named(search_count, w1_search_count, int, 0); | ||
34 | |||
35 | static int w1_enable_pullup = 1; | ||
36 | module_param_named(enable_pullup, w1_enable_pullup, int, 0); | ||
33 | 37 | ||
34 | static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | 38 | static 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 | ||
94 | int w1_add_master_device(struct w1_bus_master *master) | 102 | int 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. */ | ||
140 | err_out_kill_thread: | 182 | err_out_kill_thread: |
141 | kthread_stop(dev->thread); | 183 | kthread_stop(dev->thread); |
184 | #endif | ||
185 | err_out_rm_attr: | ||
186 | w1_destroy_master_attributes(dev); | ||
142 | err_out_free_dev: | 187 | err_out_free_dev: |
143 | w1_free_dev(dev); | 188 | w1_free_dev(dev); |
144 | 189 | ||
@@ -148,10 +193,21 @@ err_out_free_dev: | |||
148 | void __w1_remove_master_device(struct w1_master *dev) | 193 | void __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)); |