Blame view

drivers/w1/w1.c 31.6 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
a80187663   Evgeniy Polyakov   MAINTAINERS: Evge...
3
   * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
   */
  
  #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   Evgeniy Polyakov   [PATCH] w1: use k...
17
  #include <linux/kthread.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
18
  #include <linux/freezer.h>
2eb795480   Jaghathiswari Rankappagounder Natarajan   drivers: w1: add ...
19
  #include <linux/hwmon.h>
fae68031f   Daniel Mack   w1: core: match s...
20
  #include <linux/of.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

60063497a   Arun Sharma   atomic: use <linu...
22
  #include <linux/atomic.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23

de0d6dbdb   Andrew F. Davis   w1: Add subsystem...
24
  #include "w1_internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
  #include "w1_netlink.h"
de0d6dbdb   Andrew F. Davis   w1: Add subsystem...
26
  #define W1_FAMILY_DEFAULT	0
48b7de668   Christian Vogel   w1/w1.c: w1 addre...
27
  #define W1_FAMILY_DS28E04       0x1C /* for crc quirk */
de0d6dbdb   Andrew F. Davis   w1: Add subsystem...
28

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
  static int w1_timeout = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  module_param_named(timeout, w1_timeout, int, 0);
b3be177a1   David Fries   w1: format for Do...
31
  MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
50fa2951b   Andrew F. Davis   w1: Organize driv...
32
33
  
  static int w1_timeout_us = 0;
c30983569   Dmitry Khromov   w1: introduce an ...
34
  module_param_named(timeout_us, w1_timeout_us, int, 0);
a46b195ca   Wei Yongjun   w1: fix timeout_u...
35
36
  MODULE_PARM_DESC(timeout_us,
  		 "time in microseconds between automatic slave searches");
50fa2951b   Andrew F. Davis   w1: Organize driv...
37

b3be177a1   David Fries   w1: format for Do...
38
39
40
41
42
43
44
45
  /* 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   Andrew F. Davis   w1: Organize driv...
46
  int w1_max_slave_count = 64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  module_param_named(max_slave_count, w1_max_slave_count, int, 0);
b3be177a1   David Fries   w1: format for Do...
48
49
  MODULE_PARM_DESC(max_slave_count,
  	"maximum number of slaves detected in a search");
50fa2951b   Andrew F. Davis   w1: Organize driv...
50
51
  
  int w1_max_slave_ttl = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
b3be177a1   David Fries   w1: format for Do...
53
54
  MODULE_PARM_DESC(slave_ttl,
  	"Number of searches not seeing a slave before it will be removed");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
56
  DEFINE_MUTEX(w1_mlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
  LIST_HEAD(w1_masters);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
61
62
63
64
65
66
  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   Linus Torvalds   Linux-2.6.12-rc2
67
68
  static void w1_master_release(struct device *dev)
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
69
  	struct w1_master *md = dev_to_w1_master(dev);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
70
71
72
  
  	dev_dbg(dev, "%s: Releasing %s.
  ", __func__, md->name);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
73
74
  	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
  	kfree(md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
  }
  
  static void w1_slave_release(struct device *dev)
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
79
  	struct w1_slave *sl = dev_to_w1_slave(dev);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
80

9fcbbac5d   David Fries   w1: process w1 ne...
81
82
  	dev_dbg(dev, "%s: Releasing %s [%p]
  ", __func__, sl->name, sl);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
83
84
85
  
  	w1_family_put(sl->family);
  	sl->master->slave_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  }
5b187b3c0   Greg Kroah-Hartman   w1: use default a...
87
  static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  {
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
89
  	struct w1_slave *sl = dev_to_w1_slave(dev);
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
90

3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
91
92
  	return sprintf(buf, "%s
  ", sl->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  }
5b187b3c0   Greg Kroah-Hartman   w1: use default a...
94
  static DEVICE_ATTR_RO(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95

5b187b3c0   Greg Kroah-Hartman   w1: use default a...
96
  static ssize_t id_show(struct device *dev,
07e003417   David Fries   W1: w1_slave_read...
97
  	struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  {
07e003417   David Fries   W1: w1_slave_read...
99
100
  	struct w1_slave *sl = dev_to_w1_slave(dev);
  	ssize_t count = sizeof(sl->reg_num);
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
101

07e003417   David Fries   W1: w1_slave_read...
102
  	memcpy(buf, (u8 *)&sl->reg_num, count);
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
103
  	return count;
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
104
  }
5b187b3c0   Greg Kroah-Hartman   w1: use default a...
105
  static DEVICE_ATTR_RO(id);
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
106

5b187b3c0   Greg Kroah-Hartman   w1: use default a...
107
108
109
110
111
112
  static struct attribute *w1_slave_attrs[] = {
  	&dev_attr_name.attr,
  	&dev_attr_id.attr,
  	NULL,
  };
  ATTRIBUTE_GROUPS(w1_slave);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
113

d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
114
  /* Default family */
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
115

36c27a655   Greg Kroah-Hartman   w1: add attribute...
116
117
118
  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   Evgeniy Polyakov   [PATCH] w1: Added...
119
120
  {
  	struct w1_slave *sl = kobj_to_w1_slave(kobj);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
121
  	mutex_lock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
122
123
124
125
126
127
128
129
  	if (w1_reset_select_slave(sl)) {
  		count = 0;
  		goto out_up;
  	}
  
  	w1_write_block(sl->master, buf, count);
  
  out_up:
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
130
  	mutex_unlock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
131
132
  	return count;
  }
36c27a655   Greg Kroah-Hartman   w1: add attribute...
133
134
135
  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   Evgeniy Polyakov   [PATCH] w1: Added...
136
137
  {
  	struct w1_slave *sl = kobj_to_w1_slave(kobj);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
138
  	mutex_lock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
139
  	w1_read_block(sl->master, buf, count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
140
  	mutex_unlock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
141
142
  	return count;
  }
36c27a655   Greg Kroah-Hartman   w1: add attribute...
143
144
145
146
147
  static BIN_ATTR_RW(rw, PAGE_SIZE);
  
  static struct bin_attribute *w1_slave_bin_attrs[] = {
  	&bin_attr_rw,
  	NULL,
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
148
  };
36c27a655   Greg Kroah-Hartman   w1: add attribute...
149
150
151
  static const struct attribute_group w1_slave_default_group = {
  	.bin_attrs = w1_slave_bin_attrs,
  };
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
152

36c27a655   Greg Kroah-Hartman   w1: add attribute...
153
154
155
156
  static const struct attribute_group *w1_slave_default_groups[] = {
  	&w1_slave_default_group,
  	NULL,
  };
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
157

57de2dfca   Rikard Falkeborn   w1: Constify stat...
158
  static const struct w1_family_ops w1_default_fops = {
36c27a655   Greg Kroah-Hartman   w1: add attribute...
159
  	.groups		= w1_slave_default_groups,
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
160
161
162
163
164
  };
  
  static struct w1_family w1_default_family = {
  	.fops = &w1_default_fops,
  };
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
165

7eff2e7a8   Kay Sievers   Driver core: chan...
166
  static int w1_uevent(struct device *dev, struct kobj_uevent_env *env);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
167

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
  static struct bus_type w1_bus_type = {
  	.name = "w1",
  	.match = w1_master_match,
312c004d3   Kay Sievers   [PATCH] driver co...
171
  	.uevent = w1_uevent,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  };
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
173
174
  struct device_driver w1_master_driver = {
  	.name = "w1_master_driver",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  	.bus = &w1_bus_type,
  	.probe = w1_master_probe,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  };
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
178
  struct device w1_master_device = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  	.parent = NULL,
  	.bus = &w1_bus_type,
40f91de6a   Kay Sievers   w1: struct device...
181
  	.init_name = "w1 bus master",
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
182
  	.driver = &w1_master_driver,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
  	.release = &w1_master_release
  };
2c5bfdac3   Evgeniy Polyakov   [PATCH] W1: cleanups
185
  static struct device_driver w1_slave_driver = {
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
186
187
188
  	.name = "w1_slave_driver",
  	.bus = &w1_bus_type,
  };
2c5bfdac3   Evgeniy Polyakov   [PATCH] W1: cleanups
189
  #if 0
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
190
191
192
  struct device w1_slave_device = {
  	.parent = NULL,
  	.bus = &w1_bus_type,
40f91de6a   Kay Sievers   w1: struct device...
193
  	.init_name = "w1 bus slave",
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
194
  	.driver = &w1_slave_driver,
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
195
  	.release = &w1_slave_release
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
196
  };
2c5bfdac3   Evgeniy Polyakov   [PATCH] W1: cleanups
197
  #endif  /*  0  */
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
198

060b8845e   Yani Ioannou   [PATCH] Driver Co...
199
  static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
201
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
203

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
204
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  	count = sprintf(buf, "%s
  ", md->name);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
207
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  
  	return count;
  }
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
211
212
213
214
  static ssize_t w1_master_attribute_store_search(struct device * dev,
  						struct device_attribute *attr,
  						const char * buf, size_t count)
  {
6a158c0de   David Fries   W1: feature, enab...
215
  	long tmp;
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
216
  	struct w1_master *md = dev_to_w1_master(dev);
bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
217
  	int ret;
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
218

bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
219
220
221
  	ret = kstrtol(buf, 0, &tmp);
  	if (ret)
  		return ret;
6a158c0de   David Fries   W1: feature, enab...
222

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
223
  	mutex_lock(&md->mutex);
6a158c0de   David Fries   W1: feature, enab...
224
  	md->search_count = tmp;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
225
  	mutex_unlock(&md->mutex);
af8c7237b   David Fries   w1: Only wake up ...
226
227
228
  	/* Only wake if it is going to be searching. */
  	if (tmp)
  		wake_up_process(md->thread);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
229
230
231
232
233
234
235
236
  
  	return count;
  }
  
  static ssize_t w1_master_attribute_show_search(struct device *dev,
  					       struct device_attribute *attr,
  					       char *buf)
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
237
  	struct w1_master *md = dev_to_w1_master(dev);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
238
  	ssize_t count;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
239
  	mutex_lock(&md->mutex);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
240
241
  	count = sprintf(buf, "%d
  ", md->search_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
242
  	mutex_unlock(&md->mutex);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
243
244
245
  
  	return count;
  }
6a158c0de   David Fries   W1: feature, enab...
246
247
248
249
250
251
  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   Jingoo Han   drivers/w1/w1.c: ...
252
  	int ret;
6a158c0de   David Fries   W1: feature, enab...
253

bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
254
255
256
  	ret = kstrtol(buf, 0, &tmp);
  	if (ret)
  		return ret;
6a158c0de   David Fries   W1: feature, enab...
257
258
259
260
  
  	mutex_lock(&md->mutex);
  	md->enable_pullup = tmp;
  	mutex_unlock(&md->mutex);
6a158c0de   David Fries   W1: feature, enab...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
  
  	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   Yani Ioannou   [PATCH] Driver Co...
279
  static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
281
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
283

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
284
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  	count = sprintf(buf, "0x%p
  ", md->bus_master);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
287
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
290
  static ssize_t w1_master_attribute_show_timeout(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
  {
  	ssize_t count;
  	count = sprintf(buf, "%d
  ", w1_timeout);
  	return count;
  }
c30983569   Dmitry Khromov   w1: introduce an ...
297
298
299
300
301
302
303
304
  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   David Fries   w1: increase w1_m...
305
306
307
  static ssize_t w1_master_attribute_store_max_slave_count(struct device *dev,
  	struct device_attribute *attr, const char *buf, size_t count)
  {
a7155f4e2   Dan Carpenter   w1: small type cl...
308
  	int tmp;
a16130569   David Fries   w1: increase w1_m...
309
  	struct w1_master *md = dev_to_w1_master(dev);
b9c11a233   Dan Carpenter   w1: silence an un...
310
  	if (kstrtoint(buf, 0, &tmp) || tmp < 1)
a16130569   David Fries   w1: increase w1_m...
311
312
313
314
315
316
317
318
319
320
  		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   Yani Ioannou   [PATCH] Driver Co...
321
  static ssize_t w1_master_attribute_show_max_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
323
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
325

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
326
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
  	count = sprintf(buf, "%d
  ", md->max_slave_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
329
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
331
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
332
  static ssize_t w1_master_attribute_show_attempts(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
334
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
336

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
337
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  	count = sprintf(buf, "%lu
  ", md->attempts);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
340
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
343
  static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
345
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
347

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
348
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  	count = sprintf(buf, "%d
  ", md->slave_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
351
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	return count;
  }
9b4674111   David Fries   W1: be able to ma...
354
355
  static ssize_t w1_master_attribute_show_slaves(struct device *dev,
  	struct device_attribute *attr, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
357
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  	int c = PAGE_SIZE;
9fcbbac5d   David Fries   w1: process w1 ne...
359
360
  	struct list_head *ent, *n;
  	struct w1_slave *sl = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361

9fcbbac5d   David Fries   w1: process w1 ne...
362
  	mutex_lock(&md->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363

9fcbbac5d   David Fries   w1: process w1 ne...
364
365
  	list_for_each_safe(ent, n, &md->slist) {
  		sl = list_entry(ent, struct w1_slave, w1_slave_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366

9fcbbac5d   David Fries   w1: process w1 ne...
367
368
  		c -= snprintf(buf + PAGE_SIZE - c, c, "%s
  ", sl->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
370
371
372
  	if (!sl)
  		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373

9fcbbac5d   David Fries   w1: process w1 ne...
374
  	mutex_unlock(&md->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
  
  	return PAGE_SIZE - c;
  }
9b4674111   David Fries   W1: be able to ma...
378
379
380
381
382
383
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
  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   David Fries   w1: process w1 ne...
430
   * Note: must not hold list_mutex
9b4674111   David Fries   W1: be able to ma...
431
   */
70b34d2ed   David Fries   w1: new netlink c...
432
  struct w1_slave *w1_slave_search_device(struct w1_master *dev,
9b4674111   David Fries   W1: be able to ma...
433
434
435
  	struct w1_reg_num *rn)
  {
  	struct w1_slave *sl;
9fcbbac5d   David Fries   w1: process w1 ne...
436
  	mutex_lock(&dev->list_mutex);
9b4674111   David Fries   W1: be able to ma...
437
438
439
440
  	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   David Fries   w1: process w1 ne...
441
  			mutex_unlock(&dev->list_mutex);
9b4674111   David Fries   W1: be able to ma...
442
443
444
  			return sl;
  		}
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
445
  	mutex_unlock(&dev->list_mutex);
9b4674111   David Fries   W1: be able to ma...
446
447
448
449
450
451
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
  	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   David Fries   w1: process w1 ne...
504
505
506
507
  		result = w1_slave_detach(sl);
  		/* refcnt 0 means it was detached in the call */
  		if (result == 0)
  			result = count;
9b4674111   David Fries   W1: be able to ma...
508
509
510
511
512
513
514
515
516
517
  	} 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   Evgeniy Polyakov   [PATCH] w1: clean...
518
519
520
521
  #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   Evgeniy Polyakov   [PATCH] w1: Adds ...
522
523
524
525
526
  #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   Evgeniy Polyakov   [PATCH] w1: clean...
527
528
529
  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   David Fries   w1: increase w1_m...
530
  static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
531
532
  static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
  static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
c30983569   Dmitry Khromov   w1: introduce an ...
533
  static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
534
  static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
12aa4c641   Brian Swetland   w1: don't allow a...
535
536
537
538
  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   Evgeniy Polyakov   [PATCH] w1: clean...
539
540
541
542
543
544
545
546
  
  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   Dmitry Khromov   w1: introduce an ...
547
  	&w1_master_attribute_timeout_us.attr,
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
548
  	&w1_master_attribute_pointer.attr,
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
549
  	&w1_master_attribute_search.attr,
6a158c0de   David Fries   W1: feature, enab...
550
  	&w1_master_attribute_pullup.attr,
9b4674111   David Fries   W1: be able to ma...
551
552
  	&w1_master_attribute_add.attr,
  	&w1_master_attribute_remove.attr,
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
553
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  };
a890d56a9   Arvind Yadav   w1: constify attr...
555
  static const struct attribute_group w1_master_defattr_group = {
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
556
  	.attrs = w1_master_default_attrs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  };
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
558
559
560
561
  int w1_create_master_attributes(struct w1_master *master)
  {
  	return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
  }
c30c9b151   David Fries   W1: fix deadlocks...
562
  void w1_destroy_master_attributes(struct w1_master *master)
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
563
564
565
  {
  	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
  }
7eff2e7a8   Kay Sievers   Driver core: chan...
566
  static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
567
568
569
570
  {
  	struct w1_master *md = NULL;
  	struct w1_slave *sl = NULL;
  	char *event_owner, *name;
526be4162   Devendra Naga   w1: cleanup w1_ue...
571
  	int err = 0;
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
572
573
574
575
576
577
578
579
580
581
  
  	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   Kay Sievers   [PATCH] driver co...
582
583
  		dev_dbg(dev, "Unknown event.
  ");
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
584
585
  		return -EINVAL;
  	}
c6976a4eb   Andrew Morton   [PATCH] w1: warni...
586
587
  	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.
  ",
40f91de6a   Kay Sievers   w1: struct device...
588
  			event_owner, name, dev_name(dev));
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
589
590
  
  	if (dev->driver != &w1_slave_driver || !sl)
526be4162   Devendra Naga   w1: cleanup w1_ue...
591
  		goto end;
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
592

7eff2e7a8   Kay Sievers   Driver core: chan...
593
  	err = add_uevent_var(env, "W1_FID=%02X", sl->reg_num.family);
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
594
  	if (err)
526be4162   Devendra Naga   w1: cleanup w1_ue...
595
  		goto end;
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
596

7eff2e7a8   Kay Sievers   Driver core: chan...
597
598
  	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
  			     (unsigned long long)sl->reg_num.id);
526be4162   Devendra Naga   w1: cleanup w1_ue...
599
600
601
  end:
  	return err;
  }
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
602

18d7f891b   David Fries   w1: avoid recursi...
603
  static int w1_family_notify(unsigned long action, struct w1_slave *sl)
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
604
  {
07f8569fb   Rikard Falkeborn   w1: Constify stru...
605
  	const struct w1_family_ops *fops;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
606
  	int err;
36c27a655   Greg Kroah-Hartman   w1: add attribute...
607
  	fops = sl->family->fops;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
608

2962aecef   Hans-Frieder Vogt   w1 - fix fops in ...
609
610
  	if (!fops)
  		return 0;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
611
612
  	switch (action) {
  	case BUS_NOTIFY_ADD_DEVICE:
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
613
  		/* if the family driver needs to initialize something... */
36c27a655   Greg Kroah-Hartman   w1: add attribute...
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
  		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   Greg Kroah-Hartman   w1: remove race w...
633
  		}
2eb795480   Jaghathiswari Rankappagounder Natarajan   drivers: w1: add ...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
  		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   Greg Kroah-Hartman   w1: remove race w...
648
649
  		break;
  	case BUS_NOTIFY_DEL_DEVICE:
2eb795480   Jaghathiswari Rankappagounder Natarajan   drivers: w1: add ...
650
651
652
  		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info &&
  			    sl->hwmon)
  			hwmon_device_unregister(sl->hwmon);
36c27a655   Greg Kroah-Hartman   w1: add attribute...
653
  		if (fops->remove_slave)
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
654
  			sl->family->fops->remove_slave(sl);
36c27a655   Greg Kroah-Hartman   w1: add attribute...
655
656
  		if (fops->groups)
  			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
657
658
659
660
  		break;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
  static int __w1_attach_slave_device(struct w1_slave *sl)
  {
  	int err;
  
  	sl->dev.parent = &sl->master->dev;
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
666
  	sl->dev.driver = &w1_slave_driver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
  	sl->dev.bus = &w1_bus_type;
  	sl->dev.release = &w1_slave_release;
5b187b3c0   Greg Kroah-Hartman   w1: use default a...
669
  	sl->dev.groups = w1_slave_groups;
fae68031f   Daniel Mack   w1: core: match s...
670
671
  	sl->dev.of_node = of_find_matching_node(sl->master->dev.of_node,
  						sl->family->of_match_table);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672

40f91de6a   Kay Sievers   w1: struct device...
673
  	dev_set_name(&sl->dev, "%02x-%012llx",
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
674
675
676
677
678
679
  		 (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   Linus Torvalds   Linux-2.6.12-rc2
680

c6976a4eb   Andrew Morton   [PATCH] w1: warni...
681
682
  	dev_dbg(&sl->dev, "%s: registering %s as %p.
  ", __func__,
40f91de6a   Kay Sievers   w1: struct device...
683
  		dev_name(&sl->dev), sl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684

18d7f891b   David Fries   w1: avoid recursi...
685
686
  	/* suppress for w1_family_notify before sending KOBJ_ADD */
  	dev_set_uevent_suppress(&sl->dev, true);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
  	err = device_register(&sl->dev);
  	if (err < 0) {
  		dev_err(&sl->dev,
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
690
691
  			"Device registration [%s] failed. err=%d
  ",
40f91de6a   Kay Sievers   w1: struct device...
692
  			dev_name(&sl->dev), err);
0ec4eb71b   Arvind Yadav   w1: use put_devic...
693
  		put_device(&sl->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
  		return err;
  	}
18d7f891b   David Fries   w1: avoid recursi...
696
  	w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697

47eba33a0   Greg Kroah-Hartman   w1: remove race w...
698
699
  	dev_set_uevent_suppress(&sl->dev, false);
  	kobject_uevent(&sl->dev.kobj, KOBJ_ADD);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

9fcbbac5d   David Fries   w1: process w1 ne...
701
  	mutex_lock(&sl->master->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
  	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
9fcbbac5d   David Fries   w1: process w1 ne...
703
  	mutex_unlock(&sl->master->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
  
  	return 0;
  }
70b34d2ed   David Fries   w1: new netlink c...
707
  int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
  {
  	struct w1_slave *sl;
  	struct w1_family *f;
  	int err;
  	struct w1_netlink_msg msg;
dd00cc486   Yoann Padioleau   some kmalloc/mems...
713
  	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
720
  	if (!sl) {
  		dev_err(&dev->dev,
  			 "%s: failed to allocate new slave device.
  ",
  			 __func__);
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
722
723
  
  	sl->owner = THIS_MODULE;
  	sl->master = dev;
bb6709379   Michal Nazarewicz   drivers: w1: make...
724
  	set_bit(W1_SLAVE_ACTIVE, &sl->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
726
  	memset(&msg, 0, sizeof(msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
9fcbbac5d   David Fries   w1: process w1 ne...
728
729
  	atomic_set(&sl->refcnt, 1);
  	atomic_inc(&sl->master->refcnt);
2c927c0c7   Alex A. Mihaylov   w1: Fix slave cou...
730
  	dev->slave_count++;
f6887531c   Andrew Worsley   drivers: w1: Add ...
731
732
733
  	dev_info(&dev->dev, "Attaching one wire slave %02x.%012llx crc %02x
  ",
  		  rn->family, (unsigned long long)rn->id, rn->crc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734

bc04d76d6   Hans-Frieder Vogt   w1 - call request...
735
736
  	/* slave modules need to be loaded in a context with unlocked mutex */
  	mutex_unlock(&dev->mutex);
065c09563   Ingo Flaschberger   1wire: family mod...
737
  	request_module("w1-family-0x%02X", rn->family);
bc04d76d6   Hans-Frieder Vogt   w1 - call request...
738
  	mutex_lock(&dev->mutex);
8d7bda518   Alexander Stein   w1: add family ba...
739

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
  	spin_lock(&w1_flock);
  	f = w1_family_registered(rn->family);
  	if (!f) {
99c5bfe99   Evgeniy Polyakov   [PATCH] w1: Adds ...
743
  		f= &w1_default_family;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
  		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   Linus Torvalds   Linux-2.6.12-rc2
748
749
750
751
752
  	}
  	__w1_family_get(f);
  	spin_unlock(&w1_flock);
  
  	sl->family = f;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
  	err = __w1_attach_slave_device(sl);
  	if (err < 0) {
  		dev_err(&dev->dev, "%s: Attaching %s failed.
  ", __func__,
  			 sl->name);
2c927c0c7   Alex A. Mihaylov   w1: Fix slave cou...
758
  		dev->slave_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  		w1_family_put(sl->family);
d2ce4ea1a   Maciej S. Szmigiero   w1: don't leak re...
760
  		atomic_dec(&sl->master->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761
762
763
764
765
  		kfree(sl);
  		return err;
  	}
  
  	sl->ttl = dev->slave_ttl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
766

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
767
  	memcpy(msg.id.id, rn, sizeof(msg.id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
  	msg.type = W1_SLAVE_ADD;
  	w1_netlink_send(dev, &msg);
  
  	return 0;
  }
9fcbbac5d   David Fries   w1: process w1 ne...
773
  int w1_unref_slave(struct w1_slave *sl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
  {
9fcbbac5d   David Fries   w1: process w1 ne...
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
  	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   David Fries   w1: avoid recursi...
792
  		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl);
9fcbbac5d   David Fries   w1: process w1 ne...
793
794
795
796
797
798
799
800
801
802
  		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   Linus Torvalds   Linux-2.6.12-rc2
803

9fcbbac5d   David Fries   w1: process w1 ne...
804
805
806
807
808
809
810
811
812
813
814
815
  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   Linus Torvalds   Linux-2.6.12-rc2
816
  }
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
817
818
819
820
  struct w1_master *w1_search_master_id(u32 id)
  {
  	struct w1_master *dev;
  	int found = 0;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
821
  	mutex_lock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
822
823
824
825
826
827
828
  	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
  		if (dev->id == id) {
  			found = 1;
  			atomic_inc(&dev->refcnt);
  			break;
  		}
  	}
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
829
  	mutex_unlock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
830
831
832
833
834
835
836
837
838
  
  	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   Evgeniy Polyakov   [PATCH] w1: Use m...
839
  	mutex_lock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
840
  	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
9fcbbac5d   David Fries   w1: process w1 ne...
841
  		mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
842
843
844
845
846
847
848
849
850
851
  		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   David Fries   w1: process w1 ne...
852
  		mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
853
854
855
856
  
  		if (found)
  			break;
  	}
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
857
  	mutex_unlock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
858
859
860
  
  	return (found)?sl:NULL;
  }
c30c9b151   David Fries   W1: fix deadlocks...
861
  void w1_reconnect_slaves(struct w1_family *f, int attach)
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
862
  {
c30c9b151   David Fries   W1: fix deadlocks...
863
  	struct w1_slave *sl, *sln;
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
864
  	struct w1_master *dev;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
865
  	mutex_lock(&w1_mlock);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
866
  	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
c30c9b151   David Fries   W1: fix deadlocks...
867
868
869
870
  		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
  			"for family %02x.
  ", dev->name, f->fid);
  		mutex_lock(&dev->mutex);
9fcbbac5d   David Fries   w1: process w1 ne...
871
  		mutex_lock(&dev->list_mutex);
c30c9b151   David Fries   W1: fix deadlocks...
872
873
874
875
876
877
878
879
880
881
  		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   David Fries   w1: process w1 ne...
882
  				mutex_unlock(&dev->list_mutex);
c30c9b151   David Fries   W1: fix deadlocks...
883
  				memcpy(&rn, &sl->reg_num, sizeof(rn));
9fcbbac5d   David Fries   w1: process w1 ne...
884
885
886
887
888
889
  				/* 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   David Fries   W1: fix deadlocks...
890
891
892
893
894
  			}
  		}
  		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
  			"has been finished.
  ", dev->name);
9fcbbac5d   David Fries   w1: process w1 ne...
895
  		mutex_unlock(&dev->list_mutex);
c30c9b151   David Fries   W1: fix deadlocks...
896
  		mutex_unlock(&dev->mutex);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
897
  	}
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
898
  	mutex_unlock(&w1_mlock);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
899
  }
48b7de668   Christian Vogel   w1/w1.c: w1 addre...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
  static int w1_addr_crc_is_valid(struct w1_master *dev, u64 rn)
  {
  	u64 rn_le = cpu_to_le64(rn);
  	struct w1_reg_num *tmp = (struct w1_reg_num *)&rn;
  	u8 crc;
  
  	crc = w1_calc_crc8((u8 *)&rn_le, 7);
  
  	/* quirk:
  	 *   DS28E04 (1w eeprom) has strapping pins to change
  	 *   address, but will not update the crc. So normal rules
  	 *   for consistent w1 addresses are violated. We test
  	 *   with the 7 LSBs of the address forced high.
  	 *
  	 *   (char*)&rn_le = { family, addr_lsb, ..., addr_msb, crc }.
  	 */
  	if (crc != tmp->crc && tmp->family == W1_FAMILY_DS28E04) {
  		u64 corr_le = rn_le;
  
  		((u8 *)&corr_le)[1] |= 0x7f;
  		crc = w1_calc_crc8((u8 *)&corr_le, 7);
  
  		dev_info(&dev->dev, "DS28E04 crc workaround on %02x.%012llx.%02x
  ",
  			tmp->family, (unsigned long long)tmp->id, tmp->crc);
  	}
  
  	if (crc != tmp->crc) {
  		dev_dbg(&dev->dev, "w1 addr crc mismatch: %02x.%012llx.%02x != 0x%02x.
  ",
  			tmp->family, (unsigned long long)tmp->id, tmp->crc, crc);
  		return 0;
  	}
  	return 1;
  }
963bb1010   David Fries   w1: have netlink ...
935
  void w1_slave_found(struct w1_master *dev, u64 rn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
  	struct w1_slave *sl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
938
  	struct w1_reg_num *tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939

c30c9b151   David Fries   W1: fix deadlocks...
940
  	atomic_inc(&dev->refcnt);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
941

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  	tmp = (struct w1_reg_num *) &rn;
cd7b28d33   David Fries   W1: recode w1_sla...
943
944
  	sl = w1_slave_search_device(dev, tmp);
  	if (sl) {
bb6709379   Michal Nazarewicz   drivers: w1: make...
945
  		set_bit(W1_SLAVE_ACTIVE, &sl->flags);
cd7b28d33   David Fries   W1: recode w1_sla...
946
  	} else {
48b7de668   Christian Vogel   w1/w1.c: w1 addre...
947
  		if (rn && w1_addr_crc_is_valid(dev, rn))
cd7b28d33   David Fries   W1: recode w1_sla...
948
  			w1_attach_slave_device(dev, tmp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  	}
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
950

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  	atomic_dec(&dev->refcnt);
  }
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
953
  /**
b3be177a1   David Fries   w1: format for Do...
954
955
956
957
958
959
   * 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   Evgeniy Polyakov   [PATCH] w1: Added...
960
961
962
963
964
965
966
967
968
   * 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   Evgeniy Polyakov   [PATCH] w1: Added...
969
   */
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
970
  void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
971
  {
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
972
973
974
975
976
  	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   Linus Torvalds   Linux-2.6.12-rc2
977

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
978
  	search_bit = 0;
3c6955e5a   David Fries   w1: continue slav...
979
980
  	rn = dev->search_id;
  	last_rn = 0;
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
981
982
  	last_device = 0;
  	last_zero = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
  
  	desc_bit = 64;
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
985
986
  	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
  		last_rn = rn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
987
  		rn = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
988
989
990
991
992
993
  		/*
  		 * 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   NeilBrown   W1: split master ...
994
  		mutex_lock(&dev->bus_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
  		if (w1_reset_bus(dev)) {
b02f8bede   NeilBrown   W1: split master ...
996
  			mutex_unlock(&dev->bus_mutex);
2da5bf80f   Evgeniy Polyakov   [PATCH] w1: more ...
997
998
  			dev_dbg(&dev->dev, "No devices present on the wire.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
999
1000
  			break;
  		}
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
1001
1002
  		/* Do fast search on single slave bus */
  		if (dev->max_slave_count == 1) {
b02f8bede   NeilBrown   W1: split master ...
1003
  			int rv;
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
1004
  			w1_write_8(dev, W1_READ_ROM);
b02f8bede   NeilBrown   W1: split master ...
1005
1006
  			rv = w1_read_block(dev, (u8 *)&rn, 8);
  			mutex_unlock(&dev->bus_mutex);
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
1007

b02f8bede   NeilBrown   W1: split master ...
1008
  			if (rv == 8 && rn)
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
1009
1010
1011
1012
  				cb(dev, rn);
  
  			break;
  		}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1013
  		/* Start the search */
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1014
  		w1_write_8(dev, search_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1015
  		for (i = 0; i < 64; ++i) {
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1016
1017
1018
1019
1020
  			/* 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   Linus Torvalds   Linux-2.6.12-rc2
1021
  			else
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1022
  				search_bit = ((last_rn >> i) & 0x1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1023

b3be177a1   David Fries   w1: format for Do...
1024
  			/* Read two bits and write one bit */
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1025
1026
1027
1028
1029
  			triplet_ret = w1_triplet(dev, search_bit);
  
  			/* quit if no device responded */
  			if ( (triplet_ret & 0x03) == 0x03 )
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1030

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1031
1032
1033
  			/* If both directions were valid, and we took the 0 path... */
  			if (triplet_ret == 0)
  				last_zero = i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1034

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1035
1036
1037
  			/* extract the direction taken & update the device number */
  			tmp64 = (triplet_ret >> 2);
  			rn |= (tmp64 << i);
0d671b272   David Fries   W1: abort search ...
1038

421056987   David Fries   w1: fixup search ...
1039
  			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
b02f8bede   NeilBrown   W1: split master ...
1040
  				mutex_unlock(&dev->bus_mutex);
7dc8f527e   David Fries   W1: w1.c s/printk...
1041
1042
  				dev_dbg(&dev->dev, "Abort w1_search
  ");
0d671b272   David Fries   W1: abort search ...
1043
1044
  				return;
  			}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1045
  		}
b02f8bede   NeilBrown   W1: split master ...
1046
  		mutex_unlock(&dev->bus_mutex);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
1047

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1048
  		if ( (triplet_ret & 0x03) != 0x03 ) {
3c6955e5a   David Fries   w1: continue slav...
1049
  			if ((desc_bit == last_zero) || (last_zero < 0)) {
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1050
  				last_device = 1;
3c6955e5a   David Fries   w1: continue slav...
1051
1052
1053
1054
  				dev->search_id = 0;
  			} else {
  				dev->search_id = rn;
  			}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1055
  			desc_bit = last_zero;
c30c9b151   David Fries   W1: fix deadlocks...
1056
  			cb(dev, rn);
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1057
  		}
a16130569   David Fries   w1: increase w1_m...
1058
1059
1060
  
  		if (!last_device && slave_count == dev->max_slave_count &&
  			!test_bit(W1_WARN_MAX_COUNT, &dev->flags)) {
3c6955e5a   David Fries   w1: continue slav...
1061
1062
1063
1064
1065
1066
1067
  			/* 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   David Fries   w1: increase w1_m...
1068
  			dev_info(&dev->dev, "%s: max_slave_count %d reached, "
3c6955e5a   David Fries   w1: continue slav...
1069
1070
  				"will continue next search.
  ", __func__,
a16130569   David Fries   w1: increase w1_m...
1071
1072
1073
  				dev->max_slave_count);
  			set_bit(W1_WARN_MAX_COUNT, &dev->flags);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1074
1075
  	}
  }
963bb1010   David Fries   w1: have netlink ...
1076
1077
  void w1_search_process_cb(struct w1_master *dev, u8 search_type,
  	w1_slave_found_callback cb)
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1078
1079
  {
  	struct w1_slave *sl, *sln;
9fcbbac5d   David Fries   w1: process w1 ne...
1080
  	mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1081
  	list_for_each_entry(sl, &dev->slist, w1_slave_entry)
bb6709379   Michal Nazarewicz   drivers: w1: make...
1082
  		clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
9fcbbac5d   David Fries   w1: process w1 ne...
1083
  	mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1084

963bb1010   David Fries   w1: have netlink ...
1085
  	w1_search_devices(dev, search_type, cb);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1086

9fcbbac5d   David Fries   w1: process w1 ne...
1087
  	mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1088
  	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
9fcbbac5d   David Fries   w1: process w1 ne...
1089
1090
  		if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
  			mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1091
  			w1_slave_detach(sl);
9fcbbac5d   David Fries   w1: process w1 ne...
1092
1093
  			mutex_lock(&dev->list_mutex);
  		}
bb6709379   Michal Nazarewicz   drivers: w1: make...
1094
  		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1095
1096
  			sl->ttl = dev->slave_ttl;
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
1097
  	mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1098
1099
1100
1101
  
  	if (dev->search_count > 0)
  		dev->search_count--;
  }
963bb1010   David Fries   w1: have netlink ...
1102
1103
1104
1105
  static void w1_search_process(struct w1_master *dev, u8 search_type)
  {
  	w1_search_process_cb(dev, search_type, w1_slave_found);
  }
b3be177a1   David Fries   w1: format for Do...
1106
1107
1108
1109
  /**
   * w1_process_callbacks() - execute each dev->async_list callback entry
   * @dev: w1_master device
   *
a0f104644   Alexey Khoroshilov   w1: do not unlock...
1110
1111
   * The w1 master list_mutex must be held.
   *
b3be177a1   David Fries   w1: format for Do...
1112
1113
   * Return: 1 if there were commands to executed 0 otherwise
   */
9fcbbac5d   David Fries   w1: process w1 ne...
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
  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   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
  int w1_process(void *data)
  {
  	struct w1_master *dev = (struct w1_master *) data;
3c52e4e62   David Fries   W1: w1_process, b...
1136
1137
1138
  	/* As long as w1_timeout is only set by a module parameter the sleep
  	 * time can be calculated in jiffies once.
  	 */
c30983569   Dmitry Khromov   w1: introduce an ...
1139
1140
  	const unsigned long jtime =
  	  usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us);
9fcbbac5d   David Fries   w1: process w1 ne...
1141
1142
  	/* remainder if it woke up early */
  	unsigned long jremain = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143

9fcbbac5d   David Fries   w1: process w1 ne...
1144
1145
1146
  	for (;;) {
  
  		if (!jremain && dev->search_count) {
01e14d6db   David Fries   W1: don't delay s...
1147
1148
1149
1150
  			mutex_lock(&dev->mutex);
  			w1_search_process(dev, W1_SEARCH);
  			mutex_unlock(&dev->mutex);
  		}
9fcbbac5d   David Fries   w1: process w1 ne...
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
  		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   David Fries   W1: w1_process, b...
1162
  		__set_current_state(TASK_INTERRUPTIBLE);
9fcbbac5d   David Fries   w1: process w1 ne...
1163
1164
1165
1166
  		/* hold list_mutex until after interruptible to prevent loosing
  		 * the wakeup signal when async_cmd is added.
  		 */
  		mutex_unlock(&dev->list_mutex);
3c52e4e62   David Fries   W1: w1_process, b...
1167
1168
1169
1170
  		if (kthread_should_stop())
  			break;
  
  		/* Only sleep when the search is active. */
9fcbbac5d   David Fries   w1: process w1 ne...
1171
1172
1173
1174
1175
  		if (dev->search_count) {
  			if (!jremain)
  				jremain = jtime;
  			jremain = schedule_timeout(jremain);
  		}
3c52e4e62   David Fries   W1: w1_process, b...
1176
1177
  		else
  			schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
  	}
  
  	atomic_dec(&dev->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1181
1182
1183
  
  	return 0;
  }
73a98fce8   Peter Huewe   w1: add __init/__...
1184
  static int __init w1_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
1186
  {
  	int retval;
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1187
1188
  	pr_info("Driver for 1-wire Dallas network protocol.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1190
  	w1_init_netlink();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191
1192
  	retval = bus_register(&w1_bus_type);
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1193
1194
  		pr_err("Failed to register bus. err=%d.
  ", retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1195
1196
  		goto err_out_exit_init;
  	}
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1197
  	retval = driver_register(&w1_master_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1198
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1199
1200
  		pr_err("Failed to register master driver. err=%d.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
  			retval);
  		goto err_out_bus_unregister;
  	}
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1204
1205
  	retval = driver_register(&w1_slave_driver);
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1206
1207
  		pr_err("Failed to register slave driver. err=%d.
  ",
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1208
1209
1210
  			retval);
  		goto err_out_master_unregister;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1211
  	return 0;
c30c9b151   David Fries   W1: fix deadlocks...
1212
1213
  #if 0
  /* For undoing the slave register if there was a step after it. */
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1214
1215
  err_out_slave_unregister:
  	driver_unregister(&w1_slave_driver);
c30c9b151   David Fries   W1: fix deadlocks...
1216
  #endif
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1217
1218
1219
  
  err_out_master_unregister:
  	driver_unregister(&w1_master_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220
1221
1222
1223
1224
1225
1226
  
  err_out_bus_unregister:
  	bus_unregister(&w1_bus_type);
  
  err_out_exit_init:
  	return retval;
  }
73a98fce8   Peter Huewe   w1: add __init/__...
1227
  static void __exit w1_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1228
1229
  {
  	struct w1_master *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230

c30c9b151   David Fries   W1: fix deadlocks...
1231
  	/* Set netlink removal messages and some cleanup */
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
1232
  	list_for_each_entry(dev, &w1_masters, w1_master_entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
  		__w1_remove_master_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1234

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1235
  	w1_fini_netlink();
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1236
1237
  	driver_unregister(&w1_slave_driver);
  	driver_unregister(&w1_master_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
1240
1241
1242
  	bus_unregister(&w1_bus_type);
  }
  
  module_init(w1_init);
  module_exit(w1_fini);
50fa2951b   Andrew F. Davis   w1: Organize driv...
1243
1244
1245
1246
  
  MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
  MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
  MODULE_LICENSE("GPL");