Blame view
drivers/w1/w1.c
31 KB
1da177e4c Linux-2.6.12-rc2 |
1 |
/* |
a80187663 MAINTAINERS: Evge... |
2 |
* Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> |
7785925dd [PATCH] w1: clean... |
3 |
* |
1da177e4c Linux-2.6.12-rc2 |
4 5 6 7 8 9 10 11 12 |
* This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. |
1da177e4c Linux-2.6.12-rc2 |
13 14 15 16 17 18 19 20 21 22 23 24 25 |
*/ #include <linux/delay.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/list.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/timer.h> #include <linux/device.h> #include <linux/slab.h> #include <linux/sched.h> |
674a396c6 [PATCH] w1: use k... |
26 |
#include <linux/kthread.h> |
7dfb71030 [PATCH] Add inclu... |
27 |
#include <linux/freezer.h> |
2eb795480 drivers: w1: add ... |
28 |
#include <linux/hwmon.h> |
1da177e4c Linux-2.6.12-rc2 |
29 |
|
60063497a atomic: use <linu... |
30 |
#include <linux/atomic.h> |
1da177e4c Linux-2.6.12-rc2 |
31 |
|
de0d6dbdb w1: Add subsystem... |
32 |
#include "w1_internal.h" |
1da177e4c Linux-2.6.12-rc2 |
33 |
#include "w1_netlink.h" |
de0d6dbdb w1: Add subsystem... |
34 |
#define W1_FAMILY_DEFAULT 0 |
1da177e4c Linux-2.6.12-rc2 |
35 |
static int w1_timeout = 10; |
1da177e4c Linux-2.6.12-rc2 |
36 |
module_param_named(timeout, w1_timeout, int, 0); |
b3be177a1 w1: format for Do... |
37 |
MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches"); |
50fa2951b w1: Organize driv... |
38 39 |
static int w1_timeout_us = 0; |
c30983569 w1: introduce an ... |
40 |
module_param_named(timeout_us, w1_timeout_us, int, 0); |
a46b195ca w1: fix timeout_u... |
41 42 |
MODULE_PARM_DESC(timeout_us, "time in microseconds between automatic slave searches"); |
50fa2951b w1: Organize driv... |
43 |
|
b3be177a1 w1: format for Do... |
44 45 46 47 48 49 50 51 |
/* A search stops when w1_max_slave_count devices have been found in that * search. The next search will start over and detect the same set of devices * on a static 1-wire bus. Memory is not allocated based on this number, just * on the number of devices known to the kernel. Having a high number does not * consume additional resources. As a special case, if there is only one * device on the network and w1_max_slave_count is set to 1, the device id can * be read directly skipping the normal slower search process. */ |
50fa2951b w1: Organize driv... |
52 |
int w1_max_slave_count = 64; |
1da177e4c Linux-2.6.12-rc2 |
53 |
module_param_named(max_slave_count, w1_max_slave_count, int, 0); |
b3be177a1 w1: format for Do... |
54 55 |
MODULE_PARM_DESC(max_slave_count, "maximum number of slaves detected in a search"); |
50fa2951b w1: Organize driv... |
56 57 |
int w1_max_slave_ttl = 10; |
1da177e4c Linux-2.6.12-rc2 |
58 |
module_param_named(slave_ttl, w1_max_slave_ttl, int, 0); |
b3be177a1 w1: format for Do... |
59 60 |
MODULE_PARM_DESC(slave_ttl, "Number of searches not seeing a slave before it will be removed"); |
1da177e4c Linux-2.6.12-rc2 |
61 |
|
abd52a132 [PATCH] w1: Use m... |
62 |
DEFINE_MUTEX(w1_mlock); |
1da177e4c Linux-2.6.12-rc2 |
63 |
LIST_HEAD(w1_masters); |
1da177e4c Linux-2.6.12-rc2 |
64 65 66 67 68 69 70 71 72 |
static int w1_master_match(struct device *dev, struct device_driver *drv) { return 1; } static int w1_master_probe(struct device *dev) { return -ENODEV; } |
1da177e4c Linux-2.6.12-rc2 |
73 74 |
static void w1_master_release(struct device *dev) { |
db2d0008d [PATCH] w1: Added... |
75 |
struct w1_master *md = dev_to_w1_master(dev); |
3aca692d3 [PATCH] w1: Detou... |
76 77 78 |
dev_dbg(dev, "%s: Releasing %s. ", __func__, md->name); |
3aca692d3 [PATCH] w1: Detou... |
79 80 |
memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master)); kfree(md); |
1da177e4c Linux-2.6.12-rc2 |
81 82 83 84 |
} static void w1_slave_release(struct device *dev) { |
db2d0008d [PATCH] w1: Added... |
85 |
struct w1_slave *sl = dev_to_w1_slave(dev); |
3aca692d3 [PATCH] w1: Detou... |
86 |
|
9fcbbac5d w1: process w1 ne... |
87 88 |
dev_dbg(dev, "%s: Releasing %s [%p] ", __func__, sl->name, sl); |
3aca692d3 [PATCH] w1: Detou... |
89 90 91 |
w1_family_put(sl->family); sl->master->slave_count--; |
1da177e4c Linux-2.6.12-rc2 |
92 |
} |
5b187b3c0 w1: use default a... |
93 |
static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
94 |
{ |
3aca692d3 [PATCH] w1: Detou... |
95 |
struct w1_slave *sl = dev_to_w1_slave(dev); |
d2a4ef6a0 [PATCH] w1: Added... |
96 |
|
3aca692d3 [PATCH] w1: Detou... |
97 98 |
return sprintf(buf, "%s ", sl->name); |
1da177e4c Linux-2.6.12-rc2 |
99 |
} |
5b187b3c0 w1: use default a... |
100 |
static DEVICE_ATTR_RO(name); |
1da177e4c Linux-2.6.12-rc2 |
101 |
|
5b187b3c0 w1: use default a... |
102 |
static ssize_t id_show(struct device *dev, |
07e003417 W1: w1_slave_read... |
103 |
struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
104 |
{ |
07e003417 W1: w1_slave_read... |
105 106 |
struct w1_slave *sl = dev_to_w1_slave(dev); ssize_t count = sizeof(sl->reg_num); |
d2a4ef6a0 [PATCH] w1: Added... |
107 |
|
07e003417 W1: w1_slave_read... |
108 |
memcpy(buf, (u8 *)&sl->reg_num, count); |
d2a4ef6a0 [PATCH] w1: Added... |
109 |
return count; |
3aca692d3 [PATCH] w1: Detou... |
110 |
} |
5b187b3c0 w1: use default a... |
111 |
static DEVICE_ATTR_RO(id); |
d2a4ef6a0 [PATCH] w1: Added... |
112 |
|
5b187b3c0 w1: use default a... |
113 114 115 116 117 118 |
static struct attribute *w1_slave_attrs[] = { &dev_attr_name.attr, &dev_attr_id.attr, NULL, }; ATTRIBUTE_GROUPS(w1_slave); |
7785925dd [PATCH] w1: clean... |
119 |
|
d2a4ef6a0 [PATCH] w1: Added... |
120 |
/* Default family */ |
f522d2396 [PATCH] w1: Added... |
121 |
|
36c27a655 w1: add attribute... |
122 123 124 |
static ssize_t rw_write(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) |
f522d2396 [PATCH] w1: Added... |
125 126 |
{ struct w1_slave *sl = kobj_to_w1_slave(kobj); |
abd52a132 [PATCH] w1: Use m... |
127 |
mutex_lock(&sl->master->mutex); |
f522d2396 [PATCH] w1: Added... |
128 129 130 131 132 133 134 135 |
if (w1_reset_select_slave(sl)) { count = 0; goto out_up; } w1_write_block(sl->master, buf, count); out_up: |
abd52a132 [PATCH] w1: Use m... |
136 |
mutex_unlock(&sl->master->mutex); |
f522d2396 [PATCH] w1: Added... |
137 138 |
return count; } |
36c27a655 w1: add attribute... |
139 140 141 |
static ssize_t rw_read(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t off, size_t count) |
f522d2396 [PATCH] w1: Added... |
142 143 |
{ struct w1_slave *sl = kobj_to_w1_slave(kobj); |
abd52a132 [PATCH] w1: Use m... |
144 |
mutex_lock(&sl->master->mutex); |
f522d2396 [PATCH] w1: Added... |
145 |
w1_read_block(sl->master, buf, count); |
abd52a132 [PATCH] w1: Use m... |
146 |
mutex_unlock(&sl->master->mutex); |
f522d2396 [PATCH] w1: Added... |
147 148 |
return count; } |
36c27a655 w1: add attribute... |
149 150 151 152 153 |
static BIN_ATTR_RW(rw, PAGE_SIZE); static struct bin_attribute *w1_slave_bin_attrs[] = { &bin_attr_rw, NULL, |
f522d2396 [PATCH] w1: Added... |
154 |
}; |
36c27a655 w1: add attribute... |
155 156 157 |
static const struct attribute_group w1_slave_default_group = { .bin_attrs = w1_slave_bin_attrs, }; |
f522d2396 [PATCH] w1: Added... |
158 |
|
36c27a655 w1: add attribute... |
159 160 161 162 |
static const struct attribute_group *w1_slave_default_groups[] = { &w1_slave_default_group, NULL, }; |
f522d2396 [PATCH] w1: Added... |
163 164 |
static struct w1_family_ops w1_default_fops = { |
36c27a655 w1: add attribute... |
165 |
.groups = w1_slave_default_groups, |
f522d2396 [PATCH] w1: Added... |
166 167 168 169 170 |
}; static struct w1_family w1_default_family = { .fops = &w1_default_fops, }; |
d2a4ef6a0 [PATCH] w1: Added... |
171 |
|
7eff2e7a8 Driver core: chan... |
172 |
static int w1_uevent(struct device *dev, struct kobj_uevent_env *env); |
7785925dd [PATCH] w1: clean... |
173 |
|
1da177e4c Linux-2.6.12-rc2 |
174 175 176 |
static struct bus_type w1_bus_type = { .name = "w1", .match = w1_master_match, |
312c004d3 [PATCH] driver co... |
177 |
.uevent = w1_uevent, |
1da177e4c Linux-2.6.12-rc2 |
178 |
}; |
7f772ed8d [PATCH] w1: hotpl... |
179 180 |
struct device_driver w1_master_driver = { .name = "w1_master_driver", |
1da177e4c Linux-2.6.12-rc2 |
181 182 |
.bus = &w1_bus_type, .probe = w1_master_probe, |
1da177e4c Linux-2.6.12-rc2 |
183 |
}; |
7f772ed8d [PATCH] w1: hotpl... |
184 |
struct device w1_master_device = { |
1da177e4c Linux-2.6.12-rc2 |
185 186 |
.parent = NULL, .bus = &w1_bus_type, |
40f91de6a w1: struct device... |
187 |
.init_name = "w1 bus master", |
7f772ed8d [PATCH] w1: hotpl... |
188 |
.driver = &w1_master_driver, |
1da177e4c Linux-2.6.12-rc2 |
189 190 |
.release = &w1_master_release }; |
2c5bfdac3 [PATCH] W1: cleanups |
191 |
static struct device_driver w1_slave_driver = { |
7f772ed8d [PATCH] w1: hotpl... |
192 193 194 |
.name = "w1_slave_driver", .bus = &w1_bus_type, }; |
2c5bfdac3 [PATCH] W1: cleanups |
195 |
#if 0 |
7f772ed8d [PATCH] w1: hotpl... |
196 197 198 |
struct device w1_slave_device = { .parent = NULL, .bus = &w1_bus_type, |
40f91de6a w1: struct device... |
199 |
.init_name = "w1 bus slave", |
7f772ed8d [PATCH] w1: hotpl... |
200 |
.driver = &w1_slave_driver, |
3aca692d3 [PATCH] w1: Detou... |
201 |
.release = &w1_slave_release |
7f772ed8d [PATCH] w1: hotpl... |
202 |
}; |
2c5bfdac3 [PATCH] W1: cleanups |
203 |
#endif /* 0 */ |
7f772ed8d [PATCH] w1: hotpl... |
204 |
|
060b8845e [PATCH] Driver Co... |
205 |
static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
206 |
{ |
db2d0008d [PATCH] w1: Added... |
207 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
208 |
ssize_t count; |
7785925dd [PATCH] w1: clean... |
209 |
|
abd52a132 [PATCH] w1: Use m... |
210 |
mutex_lock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
211 212 |
count = sprintf(buf, "%s ", md->name); |
abd52a132 [PATCH] w1: Use m... |
213 |
mutex_unlock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 |
return count; } |
2a9d0c178 [PATCH] w1: Adds ... |
217 218 219 220 |
static ssize_t w1_master_attribute_store_search(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { |
6a158c0de W1: feature, enab... |
221 |
long tmp; |
db2d0008d [PATCH] w1: Added... |
222 |
struct w1_master *md = dev_to_w1_master(dev); |
bf4228f0e drivers/w1/w1.c: ... |
223 |
int ret; |
2a9d0c178 [PATCH] w1: Adds ... |
224 |
|
bf4228f0e drivers/w1/w1.c: ... |
225 226 227 |
ret = kstrtol(buf, 0, &tmp); if (ret) return ret; |
6a158c0de W1: feature, enab... |
228 |
|
abd52a132 [PATCH] w1: Use m... |
229 |
mutex_lock(&md->mutex); |
6a158c0de W1: feature, enab... |
230 |
md->search_count = tmp; |
abd52a132 [PATCH] w1: Use m... |
231 |
mutex_unlock(&md->mutex); |
af8c7237b w1: Only wake up ... |
232 233 234 |
/* Only wake if it is going to be searching. */ if (tmp) wake_up_process(md->thread); |
2a9d0c178 [PATCH] w1: Adds ... |
235 236 237 238 239 240 241 242 |
return count; } static ssize_t w1_master_attribute_show_search(struct device *dev, struct device_attribute *attr, char *buf) { |
db2d0008d [PATCH] w1: Added... |
243 |
struct w1_master *md = dev_to_w1_master(dev); |
2a9d0c178 [PATCH] w1: Adds ... |
244 |
ssize_t count; |
abd52a132 [PATCH] w1: Use m... |
245 |
mutex_lock(&md->mutex); |
2a9d0c178 [PATCH] w1: Adds ... |
246 247 |
count = sprintf(buf, "%d ", md->search_count); |
abd52a132 [PATCH] w1: Use m... |
248 |
mutex_unlock(&md->mutex); |
2a9d0c178 [PATCH] w1: Adds ... |
249 250 251 |
return count; } |
6a158c0de W1: feature, enab... |
252 253 254 255 256 257 |
static ssize_t w1_master_attribute_store_pullup(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { long tmp; struct w1_master *md = dev_to_w1_master(dev); |
bf4228f0e drivers/w1/w1.c: ... |
258 |
int ret; |
6a158c0de W1: feature, enab... |
259 |
|
bf4228f0e drivers/w1/w1.c: ... |
260 261 262 |
ret = kstrtol(buf, 0, &tmp); if (ret) return ret; |
6a158c0de W1: feature, enab... |
263 264 265 266 |
mutex_lock(&md->mutex); md->enable_pullup = tmp; mutex_unlock(&md->mutex); |
6a158c0de W1: feature, enab... |
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
return count; } static ssize_t w1_master_attribute_show_pullup(struct device *dev, struct device_attribute *attr, char *buf) { struct w1_master *md = dev_to_w1_master(dev); ssize_t count; mutex_lock(&md->mutex); count = sprintf(buf, "%d ", md->enable_pullup); mutex_unlock(&md->mutex); return count; } |
060b8845e [PATCH] Driver Co... |
285 |
static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
286 |
{ |
db2d0008d [PATCH] w1: Added... |
287 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
288 |
ssize_t count; |
7785925dd [PATCH] w1: clean... |
289 |
|
abd52a132 [PATCH] w1: Use m... |
290 |
mutex_lock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
291 292 |
count = sprintf(buf, "0x%p ", md->bus_master); |
abd52a132 [PATCH] w1: Use m... |
293 |
mutex_unlock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
294 295 |
return count; } |
060b8845e [PATCH] Driver Co... |
296 |
static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
297 298 299 300 301 302 |
{ ssize_t count; count = sprintf(buf, "%d ", w1_timeout); return count; } |
c30983569 w1: introduce an ... |
303 304 305 306 307 308 309 310 |
static ssize_t w1_master_attribute_show_timeout_us(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t count; count = sprintf(buf, "%d ", w1_timeout_us); return count; } |
a16130569 w1: increase w1_m... |
311 312 313 |
static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { |
a7155f4e2 w1: small type cl... |
314 |
int tmp; |
a16130569 w1: increase w1_m... |
315 |
struct w1_master *md = dev_to_w1_master(dev); |
b9c11a233 w1: silence an un... |
316 |
if (kstrtoint(buf, 0, &tmp) || tmp < 1) |
a16130569 w1: increase w1_m... |
317 318 319 320 321 322 323 324 325 326 |
return -EINVAL; mutex_lock(&md->mutex); md->max_slave_count = tmp; /* allow each time the max_slave_count is updated */ clear_bit(W1_WARN_MAX_COUNT, &md->flags); mutex_unlock(&md->mutex); return count; } |
060b8845e [PATCH] Driver Co... |
327 |
static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
328 |
{ |
db2d0008d [PATCH] w1: Added... |
329 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
330 |
ssize_t count; |
7785925dd [PATCH] w1: clean... |
331 |
|
abd52a132 [PATCH] w1: Use m... |
332 |
mutex_lock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
333 334 |
count = sprintf(buf, "%d ", md->max_slave_count); |
abd52a132 [PATCH] w1: Use m... |
335 |
mutex_unlock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
336 337 |
return count; } |
060b8845e [PATCH] Driver Co... |
338 |
static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
339 |
{ |
db2d0008d [PATCH] w1: Added... |
340 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
341 |
ssize_t count; |
7785925dd [PATCH] w1: clean... |
342 |
|
abd52a132 [PATCH] w1: Use m... |
343 |
mutex_lock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
344 345 |
count = sprintf(buf, "%lu ", md->attempts); |
abd52a132 [PATCH] w1: Use m... |
346 |
mutex_unlock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
347 348 |
return count; } |
060b8845e [PATCH] Driver Co... |
349 |
static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
350 |
{ |
db2d0008d [PATCH] w1: Added... |
351 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
352 |
ssize_t count; |
7785925dd [PATCH] w1: clean... |
353 |
|
abd52a132 [PATCH] w1: Use m... |
354 |
mutex_lock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
355 356 |
count = sprintf(buf, "%d ", md->slave_count); |
abd52a132 [PATCH] w1: Use m... |
357 |
mutex_unlock(&md->mutex); |
1da177e4c Linux-2.6.12-rc2 |
358 359 |
return count; } |
9b4674111 W1: be able to ma... |
360 361 |
static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
362 |
{ |
db2d0008d [PATCH] w1: Added... |
363 |
struct w1_master *md = dev_to_w1_master(dev); |
1da177e4c Linux-2.6.12-rc2 |
364 |
int c = PAGE_SIZE; |
9fcbbac5d w1: process w1 ne... |
365 366 |
struct list_head *ent, *n; struct w1_slave *sl = NULL; |
1da177e4c Linux-2.6.12-rc2 |
367 |
|
9fcbbac5d w1: process w1 ne... |
368 |
mutex_lock(&md->list_mutex); |
1da177e4c Linux-2.6.12-rc2 |
369 |
|
9fcbbac5d w1: process w1 ne... |
370 371 |
list_for_each_safe(ent, n, &md->slist) { sl = list_entry(ent, struct w1_slave, w1_slave_entry); |
1da177e4c Linux-2.6.12-rc2 |
372 |
|
9fcbbac5d w1: process w1 ne... |
373 374 |
c -= snprintf(buf + PAGE_SIZE - c, c, "%s ", sl->name); |
1da177e4c Linux-2.6.12-rc2 |
375 |
} |
9fcbbac5d w1: process w1 ne... |
376 377 378 |
if (!sl) c -= snprintf(buf + PAGE_SIZE - c, c, "not found. "); |
1da177e4c Linux-2.6.12-rc2 |
379 |
|
9fcbbac5d w1: process w1 ne... |
380 |
mutex_unlock(&md->list_mutex); |
1da177e4c Linux-2.6.12-rc2 |
381 382 383 |
return PAGE_SIZE - c; } |
9b4674111 W1: be able to ma... |
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
static ssize_t w1_master_attribute_show_add(struct device *dev, struct device_attribute *attr, char *buf) { int c = PAGE_SIZE; c -= snprintf(buf+PAGE_SIZE - c, c, "write device id xx-xxxxxxxxxxxx to add slave "); return PAGE_SIZE - c; } static int w1_atoreg_num(struct device *dev, const char *buf, size_t count, struct w1_reg_num *rn) { unsigned int family; unsigned long long id; int i; u64 rn64_le; /* The CRC value isn't read from the user because the sysfs directory * doesn't include it and most messages from the bus search don't * print it either. It would be unreasonable for the user to then * provide it. */ const char *error_msg = "bad slave string format, expecting " "ff-dddddddddddd "; if (buf[2] != '-') { dev_err(dev, "%s", error_msg); return -EINVAL; } i = sscanf(buf, "%02x-%012llx", &family, &id); if (i != 2) { dev_err(dev, "%s", error_msg); return -EINVAL; } rn->family = family; rn->id = id; rn64_le = cpu_to_le64(*(u64 *)rn); rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7); #if 0 dev_info(dev, "With CRC device is %02x.%012llx.%02x. ", rn->family, (unsigned long long)rn->id, rn->crc); #endif return 0; } /* Searches the slaves in the w1_master and returns a pointer or NULL. |
9fcbbac5d w1: process w1 ne... |
436 |
* Note: must not hold list_mutex |
9b4674111 W1: be able to ma... |
437 |
*/ |
70b34d2ed w1: new netlink c... |
438 |
struct w1_slave *w1_slave_search_device(struct w1_master *dev, |
9b4674111 W1: be able to ma... |
439 440 441 |
struct w1_reg_num *rn) { struct w1_slave *sl; |
9fcbbac5d w1: process w1 ne... |
442 |
mutex_lock(&dev->list_mutex); |
9b4674111 W1: be able to ma... |
443 444 445 446 |
list_for_each_entry(sl, &dev->slist, w1_slave_entry) { if (sl->reg_num.family == rn->family && sl->reg_num.id == rn->id && sl->reg_num.crc == rn->crc) { |
9fcbbac5d w1: process w1 ne... |
447 |
mutex_unlock(&dev->list_mutex); |
9b4674111 W1: be able to ma... |
448 449 450 |
return sl; } } |
9fcbbac5d w1: process w1 ne... |
451 |
mutex_unlock(&dev->list_mutex); |
9b4674111 W1: be able to ma... |
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 |
return NULL; } static ssize_t w1_master_attribute_store_add(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w1_master *md = dev_to_w1_master(dev); struct w1_reg_num rn; struct w1_slave *sl; ssize_t result = count; if (w1_atoreg_num(dev, buf, count, &rn)) return -EINVAL; mutex_lock(&md->mutex); sl = w1_slave_search_device(md, &rn); /* It would be nice to do a targeted search one the one-wire bus * for the new device to see if it is out there or not. But the * current search doesn't support that. */ if (sl) { dev_info(dev, "Device %s already exists ", sl->name); result = -EINVAL; } else { w1_attach_slave_device(md, &rn); } mutex_unlock(&md->mutex); return result; } static ssize_t w1_master_attribute_show_remove(struct device *dev, struct device_attribute *attr, char *buf) { int c = PAGE_SIZE; c -= snprintf(buf+PAGE_SIZE - c, c, "write device id xx-xxxxxxxxxxxx to remove slave "); return PAGE_SIZE - c; } static ssize_t w1_master_attribute_store_remove(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w1_master *md = dev_to_w1_master(dev); struct w1_reg_num rn; struct w1_slave *sl; ssize_t result = count; if (w1_atoreg_num(dev, buf, count, &rn)) return -EINVAL; mutex_lock(&md->mutex); sl = w1_slave_search_device(md, &rn); if (sl) { |
9fcbbac5d w1: process w1 ne... |
510 511 512 513 |
result = w1_slave_detach(sl); /* refcnt 0 means it was detached in the call */ if (result == 0) result = count; |
9b4674111 W1: be able to ma... |
514 515 516 517 518 519 520 521 522 523 |
} else { dev_info(dev, "Device %02x-%012llx doesn't exists ", rn.family, (unsigned long long)rn.id); result = -EINVAL; } mutex_unlock(&md->mutex); return result; } |
7785925dd [PATCH] w1: clean... |
524 525 526 527 |
#define W1_MASTER_ATTR_RO(_name, _mode) \ struct device_attribute w1_master_attribute_##_name = \ __ATTR(w1_master_##_name, _mode, \ w1_master_attribute_show_##_name, NULL) |
2a9d0c178 [PATCH] w1: Adds ... |
528 529 530 531 532 |
#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) |
7785925dd [PATCH] w1: clean... |
533 534 535 |
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); |
a16130569 w1: increase w1_m... |
536 |
static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP); |
7785925dd [PATCH] w1: clean... |
537 538 |
static W1_MASTER_ATTR_RO(attempts, S_IRUGO); static W1_MASTER_ATTR_RO(timeout, S_IRUGO); |
c30983569 w1: introduce an ... |
539 |
static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO); |
7785925dd [PATCH] w1: clean... |
540 |
static W1_MASTER_ATTR_RO(pointer, S_IRUGO); |
12aa4c641 w1: don't allow a... |
541 542 543 544 |
static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUSR | S_IWGRP); static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUSR | S_IWGRP); static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUSR | S_IWGRP); static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUSR | S_IWGRP); |
7785925dd [PATCH] w1: clean... |
545 546 547 548 549 550 551 552 |
static struct attribute *w1_master_default_attrs[] = { &w1_master_attribute_name.attr, &w1_master_attribute_slaves.attr, &w1_master_attribute_slave_count.attr, &w1_master_attribute_max_slave_count.attr, &w1_master_attribute_attempts.attr, &w1_master_attribute_timeout.attr, |
c30983569 w1: introduce an ... |
553 |
&w1_master_attribute_timeout_us.attr, |
7785925dd [PATCH] w1: clean... |
554 |
&w1_master_attribute_pointer.attr, |
2a9d0c178 [PATCH] w1: Adds ... |
555 |
&w1_master_attribute_search.attr, |
6a158c0de W1: feature, enab... |
556 |
&w1_master_attribute_pullup.attr, |
9b4674111 W1: be able to ma... |
557 558 |
&w1_master_attribute_add.attr, &w1_master_attribute_remove.attr, |
7785925dd [PATCH] w1: clean... |
559 |
NULL |
1da177e4c Linux-2.6.12-rc2 |
560 |
}; |
a890d56a9 w1: constify attr... |
561 |
static const struct attribute_group w1_master_defattr_group = { |
7785925dd [PATCH] w1: clean... |
562 |
.attrs = w1_master_default_attrs, |
1da177e4c Linux-2.6.12-rc2 |
563 |
}; |
7785925dd [PATCH] w1: clean... |
564 565 566 567 |
int w1_create_master_attributes(struct w1_master *master) { return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group); } |
c30c9b151 W1: fix deadlocks... |
568 |
void w1_destroy_master_attributes(struct w1_master *master) |
7785925dd [PATCH] w1: clean... |
569 570 571 |
{ sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group); } |
7eff2e7a8 Driver core: chan... |
572 |
static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) |
7f772ed8d [PATCH] w1: hotpl... |
573 574 575 576 |
{ struct w1_master *md = NULL; struct w1_slave *sl = NULL; char *event_owner, *name; |
526be4162 w1: cleanup w1_ue... |
577 |
int err = 0; |
7f772ed8d [PATCH] w1: hotpl... |
578 579 580 581 582 583 584 585 586 587 |
if (dev->driver == &w1_master_driver) { md = container_of(dev, struct w1_master, dev); event_owner = "master"; name = md->name; } else if (dev->driver == &w1_slave_driver) { sl = container_of(dev, struct w1_slave, dev); event_owner = "slave"; name = sl->name; } else { |
312c004d3 [PATCH] driver co... |
588 589 |
dev_dbg(dev, "Unknown event. "); |
7f772ed8d [PATCH] w1: hotpl... |
590 591 |
return -EINVAL; } |
c6976a4eb [PATCH] w1: warni... |
592 593 |
dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s. ", |
40f91de6a w1: struct device... |
594 |
event_owner, name, dev_name(dev)); |
7f772ed8d [PATCH] w1: hotpl... |
595 596 |
if (dev->driver != &w1_slave_driver || !sl) |
526be4162 w1: cleanup w1_ue... |
597 |
goto end; |
7f772ed8d [PATCH] w1: hotpl... |
598 |
|
7eff2e7a8 Driver core: chan... |
599 |
err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family); |
7f772ed8d [PATCH] w1: hotpl... |
600 |
if (err) |
526be4162 w1: cleanup w1_ue... |
601 |
goto end; |
7f772ed8d [PATCH] w1: hotpl... |
602 |
|
7eff2e7a8 Driver core: chan... |
603 604 |
err = add_uevent_var(env, "W1_SLAVE_ID=%024LX", (unsigned long long)sl->reg_num.id); |
526be4162 w1: cleanup w1_ue... |
605 606 607 |
end: return err; } |
7f772ed8d [PATCH] w1: hotpl... |
608 |
|
18d7f891b w1: avoid recursi... |
609 |
static int w1_family_notify(unsigned long action, struct w1_slave *sl) |
47eba33a0 w1: remove race w... |
610 |
{ |
36c27a655 w1: add attribute... |
611 |
struct w1_family_ops *fops; |
47eba33a0 w1: remove race w... |
612 |
int err; |
36c27a655 w1: add attribute... |
613 |
fops = sl->family->fops; |
47eba33a0 w1: remove race w... |
614 |
|
2962aecef w1 - fix fops in ... |
615 616 |
if (!fops) return 0; |
47eba33a0 w1: remove race w... |
617 618 |
switch (action) { case BUS_NOTIFY_ADD_DEVICE: |
47eba33a0 w1: remove race w... |
619 |
/* if the family driver needs to initialize something... */ |
36c27a655 w1: add attribute... |
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 |
if (fops->add_slave) { err = fops->add_slave(sl); if (err < 0) { dev_err(&sl->dev, "add_slave() call failed. err=%d ", err); return err; } } if (fops->groups) { err = sysfs_create_groups(&sl->dev.kobj, fops->groups); if (err) { dev_err(&sl->dev, "sysfs group creation failed. err=%d ", err); return err; } |
47eba33a0 w1: remove race w... |
639 |
} |
2eb795480 drivers: w1: add ... |
640 641 642 643 644 645 646 647 648 649 650 651 652 653 |
if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info) { struct device *hwmon = hwmon_device_register_with_info(&sl->dev, "w1_slave_temp", sl, fops->chip_info, NULL); if (IS_ERR(hwmon)) { dev_warn(&sl->dev, "could not create hwmon device "); } else { sl->hwmon = hwmon; } } |
47eba33a0 w1: remove race w... |
654 655 |
break; case BUS_NOTIFY_DEL_DEVICE: |
2eb795480 drivers: w1: add ... |
656 657 658 |
if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info && sl->hwmon) hwmon_device_unregister(sl->hwmon); |
36c27a655 w1: add attribute... |
659 |
if (fops->remove_slave) |
47eba33a0 w1: remove race w... |
660 |
sl->family->fops->remove_slave(sl); |
36c27a655 w1: add attribute... |
661 662 |
if (fops->groups) sysfs_remove_groups(&sl->dev.kobj, fops->groups); |
47eba33a0 w1: remove race w... |
663 664 665 666 |
break; } return 0; } |
1da177e4c Linux-2.6.12-rc2 |
667 668 669 670 671 |
static int __w1_attach_slave_device(struct w1_slave *sl) { int err; sl->dev.parent = &sl->master->dev; |
7f772ed8d [PATCH] w1: hotpl... |
672 |
sl->dev.driver = &w1_slave_driver; |
1da177e4c Linux-2.6.12-rc2 |
673 674 |
sl->dev.bus = &w1_bus_type; sl->dev.release = &w1_slave_release; |
5b187b3c0 w1: use default a... |
675 |
sl->dev.groups = w1_slave_groups; |
1da177e4c Linux-2.6.12-rc2 |
676 |
|
40f91de6a w1: struct device... |
677 |
dev_set_name(&sl->dev, "%02x-%012llx", |
6b7298618 [PATCH] w1: Added... |
678 679 680 681 682 683 |
(unsigned int) sl->reg_num.family, (unsigned long long) sl->reg_num.id); snprintf(&sl->name[0], sizeof(sl->name), "%02x-%012llx", (unsigned int) sl->reg_num.family, (unsigned long long) sl->reg_num.id); |
1da177e4c Linux-2.6.12-rc2 |
684 |
|
c6976a4eb [PATCH] w1: warni... |
685 686 |
dev_dbg(&sl->dev, "%s: registering %s as %p. ", __func__, |
40f91de6a w1: struct device... |
687 |
dev_name(&sl->dev), sl); |
1da177e4c Linux-2.6.12-rc2 |
688 |
|
18d7f891b w1: avoid recursi... |
689 690 |
/* suppress for w1_family_notify before sending KOBJ_ADD */ dev_set_uevent_suppress(&sl->dev, true); |
1da177e4c Linux-2.6.12-rc2 |
691 692 693 |
err = device_register(&sl->dev); if (err < 0) { dev_err(&sl->dev, |
6b7298618 [PATCH] w1: Added... |
694 695 |
"Device registration [%s] failed. err=%d ", |
40f91de6a w1: struct device... |
696 |
dev_name(&sl->dev), err); |
1da177e4c Linux-2.6.12-rc2 |
697 698 |
return err; } |
18d7f891b w1: avoid recursi... |
699 |
w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl); |
1da177e4c Linux-2.6.12-rc2 |
700 |
|
47eba33a0 w1: remove race w... |
701 702 |
dev_set_uevent_suppress(&sl->dev, false); kobject_uevent(&sl->dev.kobj, KOBJ_ADD); |
1da177e4c Linux-2.6.12-rc2 |
703 |
|
9fcbbac5d w1: process w1 ne... |
704 |
mutex_lock(&sl->master->list_mutex); |
1da177e4c Linux-2.6.12-rc2 |
705 |
list_add_tail(&sl->w1_slave_entry, &sl->master->slist); |
9fcbbac5d w1: process w1 ne... |
706 |
mutex_unlock(&sl->master->list_mutex); |
1da177e4c Linux-2.6.12-rc2 |
707 708 709 |
return 0; } |
70b34d2ed w1: new netlink c... |
710 |
int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn) |
1da177e4c Linux-2.6.12-rc2 |
711 712 713 714 715 |
{ struct w1_slave *sl; struct w1_family *f; int err; struct w1_netlink_msg msg; |
dd00cc486 some kmalloc/mems... |
716 |
sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
717 718 719 720 721 722 723 |
if (!sl) { dev_err(&dev->dev, "%s: failed to allocate new slave device. ", __func__); return -ENOMEM; } |
1da177e4c Linux-2.6.12-rc2 |
724 725 726 |
sl->owner = THIS_MODULE; sl->master = dev; |
bb6709379 drivers: w1: make... |
727 |
set_bit(W1_SLAVE_ACTIVE, &sl->flags); |
1da177e4c Linux-2.6.12-rc2 |
728 |
|
12003375a [PATCH] w1: Users... |
729 |
memset(&msg, 0, sizeof(msg)); |
1da177e4c Linux-2.6.12-rc2 |
730 |
memcpy(&sl->reg_num, rn, sizeof(sl->reg_num)); |
9fcbbac5d w1: process w1 ne... |
731 732 |
atomic_set(&sl->refcnt, 1); atomic_inc(&sl->master->refcnt); |
2c927c0c7 w1: Fix slave cou... |
733 |
dev->slave_count++; |
f6887531c drivers: w1: Add ... |
734 735 736 |
dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x ", rn->family, (unsigned long long)rn->id, rn->crc); |
1da177e4c Linux-2.6.12-rc2 |
737 |
|
bc04d76d6 w1 - call request... |
738 739 |
/* slave modules need to be loaded in a context with unlocked mutex */ mutex_unlock(&dev->mutex); |
4e0ce7053 1wire: family mod... |
740 |
request_module("w1-family-0x%02X", rn->family); |
bc04d76d6 w1 - call request... |
741 |
mutex_lock(&dev->mutex); |
8d7bda518 w1: add family ba... |
742 |
|
1da177e4c Linux-2.6.12-rc2 |
743 744 745 |
spin_lock(&w1_flock); f = w1_family_registered(rn->family); if (!f) { |
99c5bfe99 [PATCH] w1: Adds ... |
746 |
f= &w1_default_family; |
1da177e4c Linux-2.6.12-rc2 |
747 748 749 750 |
dev_info(&dev->dev, "Family %x for %02x.%012llx.%02x is not registered. ", rn->family, rn->family, (unsigned long long)rn->id, rn->crc); |
1da177e4c Linux-2.6.12-rc2 |
751 752 753 754 755 |
} __w1_family_get(f); spin_unlock(&w1_flock); sl->family = f; |
1da177e4c Linux-2.6.12-rc2 |
756 757 758 759 760 |
err = __w1_attach_slave_device(sl); if (err < 0) { dev_err(&dev->dev, "%s: Attaching %s failed. ", __func__, sl->name); |
2c927c0c7 w1: Fix slave cou... |
761 |
dev->slave_count--; |
1da177e4c Linux-2.6.12-rc2 |
762 |
w1_family_put(sl->family); |
d2ce4ea1a w1: don't leak re... |
763 |
atomic_dec(&sl->master->refcnt); |
1da177e4c Linux-2.6.12-rc2 |
764 765 766 767 768 |
kfree(sl); return err; } sl->ttl = dev->slave_ttl; |
1da177e4c Linux-2.6.12-rc2 |
769 |
|
12003375a [PATCH] w1: Users... |
770 |
memcpy(msg.id.id, rn, sizeof(msg.id)); |
1da177e4c Linux-2.6.12-rc2 |
771 772 773 774 775 |
msg.type = W1_SLAVE_ADD; w1_netlink_send(dev, &msg); return 0; } |
9fcbbac5d w1: process w1 ne... |
776 |
int w1_unref_slave(struct w1_slave *sl) |
1da177e4c Linux-2.6.12-rc2 |
777 |
{ |
9fcbbac5d w1: process w1 ne... |
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 |
struct w1_master *dev = sl->master; int refcnt; mutex_lock(&dev->list_mutex); refcnt = atomic_sub_return(1, &sl->refcnt); if (refcnt == 0) { struct w1_netlink_msg msg; dev_dbg(&sl->dev, "%s: detaching %s [%p]. ", __func__, sl->name, sl); list_del(&sl->w1_slave_entry); memset(&msg, 0, sizeof(msg)); memcpy(msg.id.id, &sl->reg_num, sizeof(msg.id)); msg.type = W1_SLAVE_REMOVE; w1_netlink_send(sl->master, &msg); |
18d7f891b w1: avoid recursi... |
795 |
w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl); |
9fcbbac5d w1: process w1 ne... |
796 797 798 799 800 801 802 803 804 805 |
device_unregister(&sl->dev); #ifdef DEBUG memset(sl, 0, sizeof(*sl)); #endif kfree(sl); } atomic_dec(&dev->refcnt); mutex_unlock(&dev->list_mutex); return refcnt; } |
1da177e4c Linux-2.6.12-rc2 |
806 |
|
9fcbbac5d w1: process w1 ne... |
807 808 809 810 811 812 813 814 815 816 817 818 |
int w1_slave_detach(struct w1_slave *sl) { /* Only detach a slave once as it decreases the refcnt each time. */ int destroy_now; mutex_lock(&sl->master->list_mutex); destroy_now = !test_bit(W1_SLAVE_DETACH, &sl->flags); set_bit(W1_SLAVE_DETACH, &sl->flags); mutex_unlock(&sl->master->list_mutex); if (destroy_now) destroy_now = !w1_unref_slave(sl); return destroy_now ? 0 : -EBUSY; |
1da177e4c Linux-2.6.12-rc2 |
819 |
} |
12003375a [PATCH] w1: Users... |
820 821 822 823 |
struct w1_master *w1_search_master_id(u32 id) { struct w1_master *dev; int found = 0; |
abd52a132 [PATCH] w1: Use m... |
824 |
mutex_lock(&w1_mlock); |
12003375a [PATCH] w1: Users... |
825 826 827 828 829 830 831 |
list_for_each_entry(dev, &w1_masters, w1_master_entry) { if (dev->id == id) { found = 1; atomic_inc(&dev->refcnt); break; } } |
abd52a132 [PATCH] w1: Use m... |
832 |
mutex_unlock(&w1_mlock); |
12003375a [PATCH] w1: Users... |
833 834 835 836 837 838 839 840 841 |
return (found)?dev:NULL; } struct w1_slave *w1_search_slave(struct w1_reg_num *id) { struct w1_master *dev; struct w1_slave *sl = NULL; int found = 0; |
abd52a132 [PATCH] w1: Use m... |
842 |
mutex_lock(&w1_mlock); |
12003375a [PATCH] w1: Users... |
843 |
list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
9fcbbac5d w1: process w1 ne... |
844 |
mutex_lock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
845 846 847 848 849 850 851 852 853 854 |
list_for_each_entry(sl, &dev->slist, w1_slave_entry) { if (sl->reg_num.family == id->family && sl->reg_num.id == id->id && sl->reg_num.crc == id->crc) { found = 1; atomic_inc(&dev->refcnt); atomic_inc(&sl->refcnt); break; } } |
9fcbbac5d w1: process w1 ne... |
855 |
mutex_unlock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
856 857 858 859 |
if (found) break; } |
abd52a132 [PATCH] w1: Use m... |
860 |
mutex_unlock(&w1_mlock); |
12003375a [PATCH] w1: Users... |
861 862 863 |
return (found)?sl:NULL; } |
c30c9b151 W1: fix deadlocks... |
864 |
void w1_reconnect_slaves(struct w1_family *f, int attach) |
6adf87bd7 [PATCH] w1: recon... |
865 |
{ |
c30c9b151 W1: fix deadlocks... |
866 |
struct w1_slave *sl, *sln; |
6adf87bd7 [PATCH] w1: recon... |
867 |
struct w1_master *dev; |
abd52a132 [PATCH] w1: Use m... |
868 |
mutex_lock(&w1_mlock); |
6adf87bd7 [PATCH] w1: recon... |
869 |
list_for_each_entry(dev, &w1_masters, w1_master_entry) { |
c30c9b151 W1: fix deadlocks... |
870 871 872 873 |
dev_dbg(&dev->dev, "Reconnecting slaves in device %s " "for family %02x. ", dev->name, f->fid); mutex_lock(&dev->mutex); |
9fcbbac5d w1: process w1 ne... |
874 |
mutex_lock(&dev->list_mutex); |
c30c9b151 W1: fix deadlocks... |
875 876 877 878 879 880 881 882 883 884 |
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { /* If it is a new family, slaves with the default * family driver and are that family will be * connected. If the family is going away, devices * matching that family are reconneced. */ if ((attach && sl->family->fid == W1_FAMILY_DEFAULT && sl->reg_num.family == f->fid) || (!attach && sl->family->fid == f->fid)) { struct w1_reg_num rn; |
9fcbbac5d w1: process w1 ne... |
885 |
mutex_unlock(&dev->list_mutex); |
c30c9b151 W1: fix deadlocks... |
886 |
memcpy(&rn, &sl->reg_num, sizeof(rn)); |
9fcbbac5d w1: process w1 ne... |
887 888 889 890 891 892 |
/* If it was already in use let the automatic * scan pick it up again later. */ if (!w1_slave_detach(sl)) w1_attach_slave_device(dev, &rn); mutex_lock(&dev->list_mutex); |
c30c9b151 W1: fix deadlocks... |
893 894 895 896 897 |
} } dev_dbg(&dev->dev, "Reconnecting slaves in device %s " "has been finished. ", dev->name); |
9fcbbac5d w1: process w1 ne... |
898 |
mutex_unlock(&dev->list_mutex); |
c30c9b151 W1: fix deadlocks... |
899 |
mutex_unlock(&dev->mutex); |
6adf87bd7 [PATCH] w1: recon... |
900 |
} |
abd52a132 [PATCH] w1: Use m... |
901 |
mutex_unlock(&w1_mlock); |
6adf87bd7 [PATCH] w1: recon... |
902 |
} |
963bb1010 w1: have netlink ... |
903 |
void w1_slave_found(struct w1_master *dev, u64 rn) |
1da177e4c Linux-2.6.12-rc2 |
904 |
{ |
1da177e4c Linux-2.6.12-rc2 |
905 |
struct w1_slave *sl; |
1da177e4c Linux-2.6.12-rc2 |
906 |
struct w1_reg_num *tmp; |
0e65f8281 [PATCH] w1: fix C... |
907 |
u64 rn_le = cpu_to_le64(rn); |
1da177e4c Linux-2.6.12-rc2 |
908 |
|
c30c9b151 W1: fix deadlocks... |
909 |
atomic_inc(&dev->refcnt); |
7785925dd [PATCH] w1: clean... |
910 |
|
1da177e4c Linux-2.6.12-rc2 |
911 |
tmp = (struct w1_reg_num *) &rn; |
cd7b28d33 W1: recode w1_sla... |
912 913 |
sl = w1_slave_search_device(dev, tmp); if (sl) { |
bb6709379 drivers: w1: make... |
914 |
set_bit(W1_SLAVE_ACTIVE, &sl->flags); |
cd7b28d33 W1: recode w1_sla... |
915 916 917 |
} else { if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7)) w1_attach_slave_device(dev, tmp); |
1da177e4c Linux-2.6.12-rc2 |
918 |
} |
7785925dd [PATCH] w1: clean... |
919 |
|
1da177e4c Linux-2.6.12-rc2 |
920 921 |
atomic_dec(&dev->refcnt); } |
6b7298618 [PATCH] w1: Added... |
922 |
/** |
b3be177a1 w1: format for Do... |
923 924 925 926 927 928 |
* w1_search() - Performs a ROM Search & registers any devices found. * @dev: The master device to search * @search_type: W1_SEARCH to search all devices, or W1_ALARM_SEARCH * to return only devices in the alarmed state * @cb: Function to call when a device is found * |
6b7298618 [PATCH] w1: Added... |
929 930 931 932 933 934 935 936 937 |
* The 1-wire search is a simple binary tree search. * For each bit of the address, we read two bits and write one bit. * The bit written will put to sleep all devies that don't match that bit. * When the two reads differ, the direction choice is obvious. * When both bits are 0, we must choose a path to take. * When we can scan all 64 bits without having to choose a path, we are done. * * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com * |
6b7298618 [PATCH] w1: Added... |
938 |
*/ |
12003375a [PATCH] w1: Users... |
939 |
void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
1da177e4c Linux-2.6.12-rc2 |
940 |
{ |
6b7298618 [PATCH] w1: Added... |
941 942 943 944 945 |
u64 last_rn, rn, tmp64; int i, slave_count = 0; int last_zero, last_device; int search_bit, desc_bit; u8 triplet_ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
946 |
|
6b7298618 [PATCH] w1: Added... |
947 |
search_bit = 0; |
3c6955e5a w1: continue slav... |
948 949 |
rn = dev->search_id; last_rn = 0; |
6b7298618 [PATCH] w1: Added... |
950 951 |
last_device = 0; last_zero = -1; |
1da177e4c Linux-2.6.12-rc2 |
952 953 |
desc_bit = 64; |
6b7298618 [PATCH] w1: Added... |
954 955 |
while ( !last_device && (slave_count++ < dev->max_slave_count) ) { last_rn = rn; |
1da177e4c Linux-2.6.12-rc2 |
956 |
rn = 0; |
1da177e4c Linux-2.6.12-rc2 |
957 958 959 960 961 962 |
/* * Reset bus and all 1-wire device state machines * so they can respond to our requests. * * Return 0 - device(s) present, 1 - no devices present. */ |
b02f8bede W1: split master ... |
963 |
mutex_lock(&dev->bus_mutex); |
1da177e4c Linux-2.6.12-rc2 |
964 |
if (w1_reset_bus(dev)) { |
b02f8bede W1: split master ... |
965 |
mutex_unlock(&dev->bus_mutex); |
2da5bf80f [PATCH] w1: more ... |
966 967 |
dev_dbg(&dev->dev, "No devices present on the wire. "); |
1da177e4c Linux-2.6.12-rc2 |
968 969 |
break; } |
c9cbf558e w1: add fast sear... |
970 971 |
/* Do fast search on single slave bus */ if (dev->max_slave_count == 1) { |
b02f8bede W1: split master ... |
972 |
int rv; |
c9cbf558e w1: add fast sear... |
973 |
w1_write_8(dev, W1_READ_ROM); |
b02f8bede W1: split master ... |
974 975 |
rv = w1_read_block(dev, (u8 *)&rn, 8); mutex_unlock(&dev->bus_mutex); |
c9cbf558e w1: add fast sear... |
976 |
|
b02f8bede W1: split master ... |
977 |
if (rv == 8 && rn) |
c9cbf558e w1: add fast sear... |
978 979 980 981 |
cb(dev, rn); break; } |
6b7298618 [PATCH] w1: Added... |
982 |
/* Start the search */ |
12003375a [PATCH] w1: Users... |
983 |
w1_write_8(dev, search_type); |
1da177e4c Linux-2.6.12-rc2 |
984 |
for (i = 0; i < 64; ++i) { |
6b7298618 [PATCH] w1: Added... |
985 986 987 988 989 |
/* Determine the direction/search bit */ if (i == desc_bit) search_bit = 1; /* took the 0 path last time, so take the 1 path */ else if (i > desc_bit) search_bit = 0; /* take the 0 path on the next branch */ |
1da177e4c Linux-2.6.12-rc2 |
990 |
else |
6b7298618 [PATCH] w1: Added... |
991 |
search_bit = ((last_rn >> i) & 0x1); |
1da177e4c Linux-2.6.12-rc2 |
992 |
|
b3be177a1 w1: format for Do... |
993 |
/* Read two bits and write one bit */ |
6b7298618 [PATCH] w1: Added... |
994 995 996 997 998 |
triplet_ret = w1_triplet(dev, search_bit); /* quit if no device responded */ if ( (triplet_ret & 0x03) == 0x03 ) break; |
1da177e4c Linux-2.6.12-rc2 |
999 |
|
6b7298618 [PATCH] w1: Added... |
1000 1001 1002 |
/* If both directions were valid, and we took the 0 path... */ if (triplet_ret == 0) last_zero = i; |
1da177e4c Linux-2.6.12-rc2 |
1003 |
|
6b7298618 [PATCH] w1: Added... |
1004 1005 1006 |
/* extract the direction taken & update the device number */ tmp64 = (triplet_ret >> 2); rn |= (tmp64 << i); |
0d671b272 W1: abort search ... |
1007 |
|
421056987 w1: fixup search ... |
1008 |
if (test_bit(W1_ABORT_SEARCH, &dev->flags)) { |
b02f8bede W1: split master ... |
1009 |
mutex_unlock(&dev->bus_mutex); |
7dc8f527e W1: w1.c s/printk... |
1010 1011 |
dev_dbg(&dev->dev, "Abort w1_search "); |
0d671b272 W1: abort search ... |
1012 1013 |
return; } |
6b7298618 [PATCH] w1: Added... |
1014 |
} |
b02f8bede W1: split master ... |
1015 |
mutex_unlock(&dev->bus_mutex); |
7785925dd [PATCH] w1: clean... |
1016 |
|
6b7298618 [PATCH] w1: Added... |
1017 |
if ( (triplet_ret & 0x03) != 0x03 ) { |
3c6955e5a w1: continue slav... |
1018 |
if ((desc_bit == last_zero) || (last_zero < 0)) { |
6b7298618 [PATCH] w1: Added... |
1019 |
last_device = 1; |
3c6955e5a w1: continue slav... |
1020 1021 1022 1023 |
dev->search_id = 0; } else { dev->search_id = rn; } |
6b7298618 [PATCH] w1: Added... |
1024 |
desc_bit = last_zero; |
c30c9b151 W1: fix deadlocks... |
1025 |
cb(dev, rn); |
6b7298618 [PATCH] w1: Added... |
1026 |
} |
a16130569 w1: increase w1_m... |
1027 1028 1029 |
if (!last_device && slave_count == dev->max_slave_count && !test_bit(W1_WARN_MAX_COUNT, &dev->flags)) { |
3c6955e5a w1: continue slav... |
1030 1031 1032 1033 1034 1035 1036 |
/* Only max_slave_count will be scanned in a search, * but it will start where it left off next search * until all ids are identified and then it will start * over. A continued search will report the previous * last id as the first id (provided it is still on the * bus). */ |
a16130569 w1: increase w1_m... |
1037 |
dev_info(&dev->dev, "%s: max_slave_count %d reached, " |
3c6955e5a w1: continue slav... |
1038 1039 |
"will continue next search. ", __func__, |
a16130569 w1: increase w1_m... |
1040 1041 1042 |
dev->max_slave_count); set_bit(W1_WARN_MAX_COUNT, &dev->flags); } |
1da177e4c Linux-2.6.12-rc2 |
1043 1044 |
} } |
963bb1010 w1: have netlink ... |
1045 1046 |
void w1_search_process_cb(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb) |
12003375a [PATCH] w1: Users... |
1047 1048 |
{ struct w1_slave *sl, *sln; |
9fcbbac5d w1: process w1 ne... |
1049 |
mutex_lock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
1050 |
list_for_each_entry(sl, &dev->slist, w1_slave_entry) |
bb6709379 drivers: w1: make... |
1051 |
clear_bit(W1_SLAVE_ACTIVE, &sl->flags); |
9fcbbac5d w1: process w1 ne... |
1052 |
mutex_unlock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
1053 |
|
963bb1010 w1: have netlink ... |
1054 |
w1_search_devices(dev, search_type, cb); |
12003375a [PATCH] w1: Users... |
1055 |
|
9fcbbac5d w1: process w1 ne... |
1056 |
mutex_lock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
1057 |
list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) { |
9fcbbac5d w1: process w1 ne... |
1058 1059 |
if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) { mutex_unlock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
1060 |
w1_slave_detach(sl); |
9fcbbac5d w1: process w1 ne... |
1061 1062 |
mutex_lock(&dev->list_mutex); } |
bb6709379 drivers: w1: make... |
1063 |
else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags)) |
12003375a [PATCH] w1: Users... |
1064 1065 |
sl->ttl = dev->slave_ttl; } |
9fcbbac5d w1: process w1 ne... |
1066 |
mutex_unlock(&dev->list_mutex); |
12003375a [PATCH] w1: Users... |
1067 1068 1069 1070 |
if (dev->search_count > 0) dev->search_count--; } |
963bb1010 w1: have netlink ... |
1071 1072 1073 1074 |
static void w1_search_process(struct w1_master *dev, u8 search_type) { w1_search_process_cb(dev, search_type, w1_slave_found); } |
b3be177a1 w1: format for Do... |
1075 1076 1077 1078 |
/** * w1_process_callbacks() - execute each dev->async_list callback entry * @dev: w1_master device * |
a0f104644 w1: do not unlock... |
1079 1080 |
* The w1 master list_mutex must be held. * |
b3be177a1 w1: format for Do... |
1081 1082 |
* Return: 1 if there were commands to executed 0 otherwise */ |
9fcbbac5d w1: process w1 ne... |
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 |
int w1_process_callbacks(struct w1_master *dev) { int ret = 0; struct w1_async_cmd *async_cmd, *async_n; /* The list can be added to in another thread, loop until it is empty */ while (!list_empty(&dev->async_list)) { list_for_each_entry_safe(async_cmd, async_n, &dev->async_list, async_entry) { /* drop the lock, if it is a search it can take a long * time */ mutex_unlock(&dev->list_mutex); async_cmd->cb(dev, async_cmd); ret = 1; mutex_lock(&dev->list_mutex); } } return ret; } |
1da177e4c Linux-2.6.12-rc2 |
1102 1103 1104 |
int w1_process(void *data) { struct w1_master *dev = (struct w1_master *) data; |
3c52e4e62 W1: w1_process, b... |
1105 1106 1107 |
/* As long as w1_timeout is only set by a module parameter the sleep * time can be calculated in jiffies once. */ |
c30983569 w1: introduce an ... |
1108 1109 |
const unsigned long jtime = usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us); |
9fcbbac5d w1: process w1 ne... |
1110 1111 |
/* remainder if it woke up early */ unsigned long jremain = 0; |
1da177e4c Linux-2.6.12-rc2 |
1112 |
|
9fcbbac5d w1: process w1 ne... |
1113 1114 1115 |
for (;;) { if (!jremain && dev->search_count) { |
01e14d6db W1: don't delay s... |
1116 1117 1118 1119 |
mutex_lock(&dev->mutex); w1_search_process(dev, W1_SEARCH); mutex_unlock(&dev->mutex); } |
9fcbbac5d w1: process w1 ne... |
1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 |
mutex_lock(&dev->list_mutex); /* Note, w1_process_callback drops the lock while processing, * but locks it again before returning. */ if (!w1_process_callbacks(dev) && jremain) { /* a wake up is either to stop the thread, process * callbacks, or search, it isn't process callbacks, so * schedule a search. */ jremain = 1; } |
3c52e4e62 W1: w1_process, b... |
1131 |
__set_current_state(TASK_INTERRUPTIBLE); |
9fcbbac5d w1: process w1 ne... |
1132 1133 1134 1135 |
/* hold list_mutex until after interruptible to prevent loosing * the wakeup signal when async_cmd is added. */ mutex_unlock(&dev->list_mutex); |
3c52e4e62 W1: w1_process, b... |
1136 1137 1138 1139 |
if (kthread_should_stop()) break; /* Only sleep when the search is active. */ |
9fcbbac5d w1: process w1 ne... |
1140 1141 1142 1143 1144 |
if (dev->search_count) { if (!jremain) jremain = jtime; jremain = schedule_timeout(jremain); } |
3c52e4e62 W1: w1_process, b... |
1145 1146 |
else schedule(); |
1da177e4c Linux-2.6.12-rc2 |
1147 1148 1149 |
} atomic_dec(&dev->refcnt); |
1da177e4c Linux-2.6.12-rc2 |
1150 1151 1152 |
return 0; } |
73a98fce8 w1: add __init/__... |
1153 |
static int __init w1_init(void) |
1da177e4c Linux-2.6.12-rc2 |
1154 1155 |
{ int retval; |
fdc9167a7 w1: use pr_* inst... |
1156 1157 |
pr_info("Driver for 1-wire Dallas network protocol. "); |
1da177e4c Linux-2.6.12-rc2 |
1158 |
|
12003375a [PATCH] w1: Users... |
1159 |
w1_init_netlink(); |
1da177e4c Linux-2.6.12-rc2 |
1160 1161 |
retval = bus_register(&w1_bus_type); if (retval) { |
fdc9167a7 w1: use pr_* inst... |
1162 1163 |
pr_err("Failed to register bus. err=%d. ", retval); |
1da177e4c Linux-2.6.12-rc2 |
1164 1165 |
goto err_out_exit_init; } |
7f772ed8d [PATCH] w1: hotpl... |
1166 |
retval = driver_register(&w1_master_driver); |
1da177e4c Linux-2.6.12-rc2 |
1167 |
if (retval) { |
fdc9167a7 w1: use pr_* inst... |
1168 1169 |
pr_err("Failed to register master driver. err=%d. ", |
1da177e4c Linux-2.6.12-rc2 |
1170 1171 1172 |
retval); goto err_out_bus_unregister; } |
7f772ed8d [PATCH] w1: hotpl... |
1173 1174 |
retval = driver_register(&w1_slave_driver); if (retval) { |
fdc9167a7 w1: use pr_* inst... |
1175 1176 |
pr_err("Failed to register slave driver. err=%d. ", |
7f772ed8d [PATCH] w1: hotpl... |
1177 1178 1179 |
retval); goto err_out_master_unregister; } |
1da177e4c Linux-2.6.12-rc2 |
1180 |
return 0; |
c30c9b151 W1: fix deadlocks... |
1181 1182 |
#if 0 /* For undoing the slave register if there was a step after it. */ |
7f772ed8d [PATCH] w1: hotpl... |
1183 1184 |
err_out_slave_unregister: driver_unregister(&w1_slave_driver); |
c30c9b151 W1: fix deadlocks... |
1185 |
#endif |
7f772ed8d [PATCH] w1: hotpl... |
1186 1187 1188 |
err_out_master_unregister: driver_unregister(&w1_master_driver); |
1da177e4c Linux-2.6.12-rc2 |
1189 1190 1191 1192 1193 1194 1195 |
err_out_bus_unregister: bus_unregister(&w1_bus_type); err_out_exit_init: return retval; } |
73a98fce8 w1: add __init/__... |
1196 |
static void __exit w1_fini(void) |
1da177e4c Linux-2.6.12-rc2 |
1197 1198 |
{ struct w1_master *dev; |
1da177e4c Linux-2.6.12-rc2 |
1199 |
|
c30c9b151 W1: fix deadlocks... |
1200 |
/* Set netlink removal messages and some cleanup */ |
7785925dd [PATCH] w1: clean... |
1201 |
list_for_each_entry(dev, &w1_masters, w1_master_entry) |
1da177e4c Linux-2.6.12-rc2 |
1202 |
__w1_remove_master_device(dev); |
1da177e4c Linux-2.6.12-rc2 |
1203 |
|
12003375a [PATCH] w1: Users... |
1204 |
w1_fini_netlink(); |
7f772ed8d [PATCH] w1: hotpl... |
1205 1206 |
driver_unregister(&w1_slave_driver); driver_unregister(&w1_master_driver); |
1da177e4c Linux-2.6.12-rc2 |
1207 1208 1209 1210 1211 |
bus_unregister(&w1_bus_type); } module_init(w1_init); module_exit(w1_fini); |
50fa2951b w1: Organize driv... |
1212 1213 1214 1215 |
MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>"); MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol."); MODULE_LICENSE("GPL"); |