Blame view

drivers/w1/w1.c 31 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
a80187663   Evgeniy Polyakov   MAINTAINERS: Evge...
2
   * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
3
   *
1da177e4c   Linus Torvalds   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   Linus Torvalds   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   Evgeniy Polyakov   [PATCH] w1: use k...
26
  #include <linux/kthread.h>
7dfb71030   Nigel Cunningham   [PATCH] Add inclu...
27
  #include <linux/freezer.h>
2eb795480   Jaghathiswari Rankappagounder Natarajan   drivers: w1: add ...
28
  #include <linux/hwmon.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29

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

de0d6dbdb   Andrew F. Davis   w1: Add subsystem...
32
  #include "w1_internal.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  #include "w1_netlink.h"
de0d6dbdb   Andrew F. Davis   w1: Add subsystem...
34
  #define W1_FAMILY_DEFAULT	0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  static int w1_timeout = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  module_param_named(timeout, w1_timeout, int, 0);
b3be177a1   David Fries   w1: format for Do...
37
  MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
50fa2951b   Andrew F. Davis   w1: Organize driv...
38
39
  
  static int w1_timeout_us = 0;
c30983569   Dmitry Khromov   w1: introduce an ...
40
  module_param_named(timeout_us, w1_timeout_us, int, 0);
a46b195ca   Wei Yongjun   w1: fix timeout_u...
41
42
  MODULE_PARM_DESC(timeout_us,
  		 "time in microseconds between automatic slave searches");
50fa2951b   Andrew F. Davis   w1: Organize driv...
43

b3be177a1   David Fries   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   Andrew F. Davis   w1: Organize driv...
52
  int w1_max_slave_count = 64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  module_param_named(max_slave_count, w1_max_slave_count, int, 0);
b3be177a1   David Fries   w1: format for Do...
54
55
  MODULE_PARM_DESC(max_slave_count,
  	"maximum number of slaves detected in a search");
50fa2951b   Andrew F. Davis   w1: Organize driv...
56
57
  
  int w1_max_slave_ttl = 10;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
  module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
b3be177a1   David Fries   w1: format for Do...
59
60
  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
61

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
62
  DEFINE_MUTEX(w1_mlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
  LIST_HEAD(w1_masters);
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
73
74
  static void w1_master_release(struct device *dev)
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
75
  	struct w1_master *md = dev_to_w1_master(dev);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
76
77
78
  
  	dev_dbg(dev, "%s: Releasing %s.
  ", __func__, md->name);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
79
80
  	memset(md, 0, sizeof(struct w1_master) + sizeof(struct w1_bus_master));
  	kfree(md);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
84
  }
  
  static void w1_slave_release(struct device *dev)
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
85
  	struct w1_slave *sl = dev_to_w1_slave(dev);
3aca692d3   Evgeniy Polyakov   [PATCH] w1: Detou...
86

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

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

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

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

5b187b3c0   Greg Kroah-Hartman   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   Evgeniy Polyakov   [PATCH] w1: clean...
119

d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
120
  /* Default family */
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
121

36c27a655   Greg Kroah-Hartman   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   Evgeniy Polyakov   [PATCH] w1: Added...
125
126
  {
  	struct w1_slave *sl = kobj_to_w1_slave(kobj);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
127
  	mutex_lock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [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   Evgeniy Polyakov   [PATCH] w1: Use m...
136
  	mutex_unlock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
137
138
  	return count;
  }
36c27a655   Greg Kroah-Hartman   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   Evgeniy Polyakov   [PATCH] w1: Added...
142
143
  {
  	struct w1_slave *sl = kobj_to_w1_slave(kobj);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
144
  	mutex_lock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
145
  	w1_read_block(sl->master, buf, count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
146
  	mutex_unlock(&sl->master->mutex);
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
147
148
  	return count;
  }
36c27a655   Greg Kroah-Hartman   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   Evgeniy Polyakov   [PATCH] w1: Added...
154
  };
36c27a655   Greg Kroah-Hartman   w1: add attribute...
155
156
157
  static const struct attribute_group w1_slave_default_group = {
  	.bin_attrs = w1_slave_bin_attrs,
  };
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
158

36c27a655   Greg Kroah-Hartman   w1: add attribute...
159
160
161
162
  static const struct attribute_group *w1_slave_default_groups[] = {
  	&w1_slave_default_group,
  	NULL,
  };
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
163
164
  
  static struct w1_family_ops w1_default_fops = {
36c27a655   Greg Kroah-Hartman   w1: add attribute...
165
  	.groups		= w1_slave_default_groups,
f522d2396   Evgeniy Polyakov   [PATCH] w1: Added...
166
167
168
169
170
  };
  
  static struct w1_family w1_default_family = {
  	.fops = &w1_default_fops,
  };
d2a4ef6a0   Evgeniy Polyakov   [PATCH] w1: Added...
171

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

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

060b8845e   Yani Ioannou   [PATCH] Driver Co...
205
  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
206
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
207
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
209

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
210
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
  	count = sprintf(buf, "%s
  ", md->name);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
213
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  
  	return count;
  }
2a9d0c178   Evgeniy Polyakov   [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   David Fries   W1: feature, enab...
221
  	long tmp;
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
222
  	struct w1_master *md = dev_to_w1_master(dev);
bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
223
  	int ret;
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
224

bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
225
226
227
  	ret = kstrtol(buf, 0, &tmp);
  	if (ret)
  		return ret;
6a158c0de   David Fries   W1: feature, enab...
228

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
229
  	mutex_lock(&md->mutex);
6a158c0de   David Fries   W1: feature, enab...
230
  	md->search_count = tmp;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
231
  	mutex_unlock(&md->mutex);
af8c7237b   David Fries   w1: Only wake up ...
232
233
234
  	/* Only wake if it is going to be searching. */
  	if (tmp)
  		wake_up_process(md->thread);
2a9d0c178   Evgeniy Polyakov   [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   Evgeniy Polyakov   [PATCH] w1: Added...
243
  	struct w1_master *md = dev_to_w1_master(dev);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
244
  	ssize_t count;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
245
  	mutex_lock(&md->mutex);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
246
247
  	count = sprintf(buf, "%d
  ", md->search_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
248
  	mutex_unlock(&md->mutex);
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
249
250
251
  
  	return count;
  }
6a158c0de   David Fries   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   Jingoo Han   drivers/w1/w1.c: ...
258
  	int ret;
6a158c0de   David Fries   W1: feature, enab...
259

bf4228f0e   Jingoo Han   drivers/w1/w1.c: ...
260
261
262
  	ret = kstrtol(buf, 0, &tmp);
  	if (ret)
  		return ret;
6a158c0de   David Fries   W1: feature, enab...
263
264
265
266
  
  	mutex_lock(&md->mutex);
  	md->enable_pullup = tmp;
  	mutex_unlock(&md->mutex);
6a158c0de   David Fries   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   Yani Ioannou   [PATCH] Driver Co...
285
  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
286
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
287
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
289

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
290
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  	count = sprintf(buf, "0x%p
  ", md->bus_master);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
293
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
295
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
296
  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
297
298
299
300
301
302
  {
  	ssize_t count;
  	count = sprintf(buf, "%d
  ", w1_timeout);
  	return count;
  }
c30983569   Dmitry Khromov   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   David Fries   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   Dan Carpenter   w1: small type cl...
314
  	int tmp;
a16130569   David Fries   w1: increase w1_m...
315
  	struct w1_master *md = dev_to_w1_master(dev);
b9c11a233   Dan Carpenter   w1: silence an un...
316
  	if (kstrtoint(buf, 0, &tmp) || tmp < 1)
a16130569   David Fries   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   Yani Ioannou   [PATCH] Driver Co...
327
  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
328
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
329
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
331

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
332
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
334
  	count = sprintf(buf, "%d
  ", md->max_slave_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
335
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
338
  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
339
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
340
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
342

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
343
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
  	count = sprintf(buf, "%lu
  ", md->attempts);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
346
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  	return count;
  }
060b8845e   Yani Ioannou   [PATCH] Driver Co...
349
  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
350
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
351
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	ssize_t count;
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
353

abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
354
  	mutex_lock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
  	count = sprintf(buf, "%d
  ", md->slave_count);
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
357
  	mutex_unlock(&md->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
  	return count;
  }
9b4674111   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
362
  {
db2d0008d   Evgeniy Polyakov   [PATCH] w1: Added...
363
  	struct w1_master *md = dev_to_w1_master(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  	int c = PAGE_SIZE;
9fcbbac5d   David Fries   w1: process w1 ne...
365
366
  	struct list_head *ent, *n;
  	struct w1_slave *sl = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367

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

9fcbbac5d   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
372

9fcbbac5d   David Fries   w1: process w1 ne...
373
374
  		c -= snprintf(buf + PAGE_SIZE - c, c, "%s
  ", sl->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
376
377
378
  	if (!sl)
  		c -= snprintf(buf + PAGE_SIZE - c, c, "not found.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379

9fcbbac5d   David Fries   w1: process w1 ne...
380
  	mutex_unlock(&md->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
  
  	return PAGE_SIZE - c;
  }
9b4674111   David Fries   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   David Fries   w1: process w1 ne...
436
   * Note: must not hold list_mutex
9b4674111   David Fries   W1: be able to ma...
437
   */
70b34d2ed   David Fries   w1: new netlink c...
438
  struct w1_slave *w1_slave_search_device(struct w1_master *dev,
9b4674111   David Fries   W1: be able to ma...
439
440
441
  	struct w1_reg_num *rn)
  {
  	struct w1_slave *sl;
9fcbbac5d   David Fries   w1: process w1 ne...
442
  	mutex_lock(&dev->list_mutex);
9b4674111   David Fries   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   David Fries   w1: process w1 ne...
447
  			mutex_unlock(&dev->list_mutex);
9b4674111   David Fries   W1: be able to ma...
448
449
450
  			return sl;
  		}
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
451
  	mutex_unlock(&dev->list_mutex);
9b4674111   David Fries   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   David Fries   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   David Fries   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   Evgeniy Polyakov   [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   Evgeniy Polyakov   [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   Evgeniy Polyakov   [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   David Fries   w1: increase w1_m...
536
  static W1_MASTER_ATTR_RW(max_slave_count, S_IRUGO | S_IWUSR | S_IWGRP);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
537
538
  static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
  static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
c30983569   Dmitry Khromov   w1: introduce an ...
539
  static W1_MASTER_ATTR_RO(timeout_us, S_IRUGO);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
540
  static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
12aa4c641   Brian Swetland   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   Evgeniy Polyakov   [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   Dmitry Khromov   w1: introduce an ...
553
  	&w1_master_attribute_timeout_us.attr,
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
554
  	&w1_master_attribute_pointer.attr,
2a9d0c178   Evgeniy Polyakov   [PATCH] w1: Adds ...
555
  	&w1_master_attribute_search.attr,
6a158c0de   David Fries   W1: feature, enab...
556
  	&w1_master_attribute_pullup.attr,
9b4674111   David Fries   W1: be able to ma...
557
558
  	&w1_master_attribute_add.attr,
  	&w1_master_attribute_remove.attr,
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
559
  	NULL
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
  };
a890d56a9   Arvind Yadav   w1: constify attr...
561
  static const struct attribute_group w1_master_defattr_group = {
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
562
  	.attrs = w1_master_default_attrs,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  };
7785925dd   Evgeniy Polyakov   [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   David Fries   W1: fix deadlocks...
568
  void w1_destroy_master_attributes(struct w1_master *master)
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
569
570
571
  {
  	sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
  }
7eff2e7a8   Kay Sievers   Driver core: chan...
572
  static int w1_uevent(struct device *dev, struct kobj_uevent_env *env)
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
573
574
575
576
  {
  	struct w1_master *md = NULL;
  	struct w1_slave *sl = NULL;
  	char *event_owner, *name;
526be4162   Devendra Naga   w1: cleanup w1_ue...
577
  	int err = 0;
7f772ed8d   Evgeniy Polyakov   [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   Kay Sievers   [PATCH] driver co...
588
589
  		dev_dbg(dev, "Unknown event.
  ");
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
590
591
  		return -EINVAL;
  	}
c6976a4eb   Andrew Morton   [PATCH] w1: warni...
592
593
  	dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.
  ",
40f91de6a   Kay Sievers   w1: struct device...
594
  			event_owner, name, dev_name(dev));
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
595
596
  
  	if (dev->driver != &w1_slave_driver || !sl)
526be4162   Devendra Naga   w1: cleanup w1_ue...
597
  		goto end;
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
598

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

7eff2e7a8   Kay Sievers   Driver core: chan...
603
604
  	err = add_uevent_var(env, "W1_SLAVE_ID=%024LX",
  			     (unsigned long long)sl->reg_num.id);
526be4162   Devendra Naga   w1: cleanup w1_ue...
605
606
607
  end:
  	return err;
  }
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
608

18d7f891b   David Fries   w1: avoid recursi...
609
  static int w1_family_notify(unsigned long action, struct w1_slave *sl)
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
610
  {
36c27a655   Greg Kroah-Hartman   w1: add attribute...
611
  	struct w1_family_ops *fops;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
612
  	int err;
36c27a655   Greg Kroah-Hartman   w1: add attribute...
613
  	fops = sl->family->fops;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
614

2962aecef   Hans-Frieder Vogt   w1 - fix fops in ...
615
616
  	if (!fops)
  		return 0;
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
617
618
  	switch (action) {
  	case BUS_NOTIFY_ADD_DEVICE:
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
619
  		/* if the family driver needs to initialize something... */
36c27a655   Greg Kroah-Hartman   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   Greg Kroah-Hartman   w1: remove race w...
639
  		}
2eb795480   Jaghathiswari Rankappagounder Natarajan   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   Greg Kroah-Hartman   w1: remove race w...
654
655
  		break;
  	case BUS_NOTIFY_DEL_DEVICE:
2eb795480   Jaghathiswari Rankappagounder Natarajan   drivers: w1: add ...
656
657
658
  		if (IS_REACHABLE(CONFIG_HWMON) && fops->chip_info &&
  			    sl->hwmon)
  			hwmon_device_unregister(sl->hwmon);
36c27a655   Greg Kroah-Hartman   w1: add attribute...
659
  		if (fops->remove_slave)
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
660
  			sl->family->fops->remove_slave(sl);
36c27a655   Greg Kroah-Hartman   w1: add attribute...
661
662
  		if (fops->groups)
  			sysfs_remove_groups(&sl->dev.kobj, fops->groups);
47eba33a0   Greg Kroah-Hartman   w1: remove race w...
663
664
665
666
  		break;
  	}
  	return 0;
  }
1da177e4c   Linus Torvalds   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   Evgeniy Polyakov   [PATCH] w1: hotpl...
672
  	sl->dev.driver = &w1_slave_driver;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  	sl->dev.bus = &w1_bus_type;
  	sl->dev.release = &w1_slave_release;
5b187b3c0   Greg Kroah-Hartman   w1: use default a...
675
  	sl->dev.groups = w1_slave_groups;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676

40f91de6a   Kay Sievers   w1: struct device...
677
  	dev_set_name(&sl->dev, "%02x-%012llx",
6b7298618   Evgeniy Polyakov   [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   Linus Torvalds   Linux-2.6.12-rc2
684

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

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

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

9fcbbac5d   David Fries   w1: process w1 ne...
704
  	mutex_lock(&sl->master->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  	list_add_tail(&sl->w1_slave_entry, &sl->master->slist);
9fcbbac5d   David Fries   w1: process w1 ne...
706
  	mutex_unlock(&sl->master->list_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
709
  
  	return 0;
  }
70b34d2ed   David Fries   w1: new netlink c...
710
  int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
1da177e4c   Linus Torvalds   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   Yoann Padioleau   some kmalloc/mems...
716
  	sl = kzalloc(sizeof(struct w1_slave), GFP_KERNEL);
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
724
725
726
  
  	sl->owner = THIS_MODULE;
  	sl->master = dev;
bb6709379   Michal Nazarewicz   drivers: w1: make...
727
  	set_bit(W1_SLAVE_ACTIVE, &sl->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
729
  	memset(&msg, 0, sizeof(msg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  	memcpy(&sl->reg_num, rn, sizeof(sl->reg_num));
9fcbbac5d   David Fries   w1: process w1 ne...
731
732
  	atomic_set(&sl->refcnt, 1);
  	atomic_inc(&sl->master->refcnt);
2c927c0c7   Alex A. Mihaylov   w1: Fix slave cou...
733
  	dev->slave_count++;
f6887531c   Andrew Worsley   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   Linus Torvalds   Linux-2.6.12-rc2
737

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
745
  	spin_lock(&w1_flock);
  	f = w1_family_registered(rn->family);
  	if (!f) {
99c5bfe99   Evgeniy Polyakov   [PATCH] w1: Adds ...
746
  		f= &w1_default_family;
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
751
752
753
754
755
  	}
  	__w1_family_get(f);
  	spin_unlock(&w1_flock);
  
  	sl->family = f;
1da177e4c   Linus Torvalds   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   Alex A. Mihaylov   w1: Fix slave cou...
761
  		dev->slave_count--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  		w1_family_put(sl->family);
d2ce4ea1a   Maciej S. Szmigiero   w1: don't leak re...
763
  		atomic_dec(&sl->master->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
767
768
  		kfree(sl);
  		return err;
  	}
  
  	sl->ttl = dev->slave_ttl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
770
  	memcpy(msg.id.id, rn, sizeof(msg.id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
  	msg.type = W1_SLAVE_ADD;
  	w1_netlink_send(dev, &msg);
  
  	return 0;
  }
9fcbbac5d   David Fries   w1: process w1 ne...
776
  int w1_unref_slave(struct w1_slave *sl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  {
9fcbbac5d   David Fries   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   David Fries   w1: avoid recursi...
795
  		w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl);
9fcbbac5d   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
806

9fcbbac5d   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
819
  }
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
820
821
822
823
  struct w1_master *w1_search_master_id(u32 id)
  {
  	struct w1_master *dev;
  	int found = 0;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
824
  	mutex_lock(&w1_mlock);
12003375a   Evgeniy Polyakov   [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   Evgeniy Polyakov   [PATCH] w1: Use m...
832
  	mutex_unlock(&w1_mlock);
12003375a   Evgeniy Polyakov   [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   Evgeniy Polyakov   [PATCH] w1: Use m...
842
  	mutex_lock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
843
  	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
9fcbbac5d   David Fries   w1: process w1 ne...
844
  		mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [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   David Fries   w1: process w1 ne...
855
  		mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
856
857
858
859
  
  		if (found)
  			break;
  	}
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
860
  	mutex_unlock(&w1_mlock);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
861
862
863
  
  	return (found)?sl:NULL;
  }
c30c9b151   David Fries   W1: fix deadlocks...
864
  void w1_reconnect_slaves(struct w1_family *f, int attach)
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
865
  {
c30c9b151   David Fries   W1: fix deadlocks...
866
  	struct w1_slave *sl, *sln;
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
867
  	struct w1_master *dev;
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
868
  	mutex_lock(&w1_mlock);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
869
  	list_for_each_entry(dev, &w1_masters, w1_master_entry) {
c30c9b151   David Fries   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   David Fries   w1: process w1 ne...
874
  		mutex_lock(&dev->list_mutex);
c30c9b151   David Fries   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   David Fries   w1: process w1 ne...
885
  				mutex_unlock(&dev->list_mutex);
c30c9b151   David Fries   W1: fix deadlocks...
886
  				memcpy(&rn, &sl->reg_num, sizeof(rn));
9fcbbac5d   David Fries   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   David Fries   W1: fix deadlocks...
893
894
895
896
897
  			}
  		}
  		dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
  			"has been finished.
  ", dev->name);
9fcbbac5d   David Fries   w1: process w1 ne...
898
  		mutex_unlock(&dev->list_mutex);
c30c9b151   David Fries   W1: fix deadlocks...
899
  		mutex_unlock(&dev->mutex);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
900
  	}
abd52a132   Evgeniy Polyakov   [PATCH] w1: Use m...
901
  	mutex_unlock(&w1_mlock);
6adf87bd7   Evgeniy Polyakov   [PATCH] w1: recon...
902
  }
963bb1010   David Fries   w1: have netlink ...
903
  void w1_slave_found(struct w1_master *dev, u64 rn)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
904
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  	struct w1_slave *sl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
  	struct w1_reg_num *tmp;
0e65f8281   Evgeniy Polyakov   [PATCH] w1: fix C...
907
  	u64 rn_le = cpu_to_le64(rn);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	tmp = (struct w1_reg_num *) &rn;
cd7b28d33   David Fries   W1: recode w1_sla...
912
913
  	sl = w1_slave_search_device(dev, tmp);
  	if (sl) {
bb6709379   Michal Nazarewicz   drivers: w1: make...
914
  		set_bit(W1_SLAVE_ACTIVE, &sl->flags);
cd7b28d33   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
918
  	}
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
919

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
  	atomic_dec(&dev->refcnt);
  }
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
922
  /**
b3be177a1   David Fries   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   Evgeniy Polyakov   [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   Evgeniy Polyakov   [PATCH] w1: Added...
938
   */
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
939
  void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
  {
6b7298618   Evgeniy Polyakov   [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   Linus Torvalds   Linux-2.6.12-rc2
946

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
947
  	search_bit = 0;
3c6955e5a   David Fries   w1: continue slav...
948
949
  	rn = dev->search_id;
  	last_rn = 0;
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
950
951
  	last_device = 0;
  	last_zero = -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
953
  
  	desc_bit = 64;
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
954
955
  	while ( !last_device && (slave_count++ < dev->max_slave_count) ) {
  		last_rn = rn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
  		rn = 0;
1da177e4c   Linus Torvalds   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   NeilBrown   W1: split master ...
963
  		mutex_lock(&dev->bus_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
  		if (w1_reset_bus(dev)) {
b02f8bede   NeilBrown   W1: split master ...
965
  			mutex_unlock(&dev->bus_mutex);
2da5bf80f   Evgeniy Polyakov   [PATCH] w1: more ...
966
967
  			dev_dbg(&dev->dev, "No devices present on the wire.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
  			break;
  		}
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
970
971
  		/* Do fast search on single slave bus */
  		if (dev->max_slave_count == 1) {
b02f8bede   NeilBrown   W1: split master ...
972
  			int rv;
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
973
  			w1_write_8(dev, W1_READ_ROM);
b02f8bede   NeilBrown   W1: split master ...
974
975
  			rv = w1_read_block(dev, (u8 *)&rn, 8);
  			mutex_unlock(&dev->bus_mutex);
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
976

b02f8bede   NeilBrown   W1: split master ...
977
  			if (rv == 8 && rn)
c9cbf558e   Evgeniy Polyakov   w1: add fast sear...
978
979
980
981
  				cb(dev, rn);
  
  			break;
  		}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
982
  		/* Start the search */
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
983
  		w1_write_8(dev, search_type);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  		for (i = 0; i < 64; ++i) {
6b7298618   Evgeniy Polyakov   [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   Linus Torvalds   Linux-2.6.12-rc2
990
  			else
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
991
  				search_bit = ((last_rn >> i) & 0x1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992

b3be177a1   David Fries   w1: format for Do...
993
  			/* Read two bits and write one bit */
6b7298618   Evgeniy Polyakov   [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   Linus Torvalds   Linux-2.6.12-rc2
999

6b7298618   Evgeniy Polyakov   [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   Linus Torvalds   Linux-2.6.12-rc2
1003

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

421056987   David Fries   w1: fixup search ...
1008
  			if (test_bit(W1_ABORT_SEARCH, &dev->flags)) {
b02f8bede   NeilBrown   W1: split master ...
1009
  				mutex_unlock(&dev->bus_mutex);
7dc8f527e   David Fries   W1: w1.c s/printk...
1010
1011
  				dev_dbg(&dev->dev, "Abort w1_search
  ");
0d671b272   David Fries   W1: abort search ...
1012
1013
  				return;
  			}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1014
  		}
b02f8bede   NeilBrown   W1: split master ...
1015
  		mutex_unlock(&dev->bus_mutex);
7785925dd   Evgeniy Polyakov   [PATCH] w1: clean...
1016

6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1017
  		if ( (triplet_ret & 0x03) != 0x03 ) {
3c6955e5a   David Fries   w1: continue slav...
1018
  			if ((desc_bit == last_zero) || (last_zero < 0)) {
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1019
  				last_device = 1;
3c6955e5a   David Fries   w1: continue slav...
1020
1021
1022
1023
  				dev->search_id = 0;
  			} else {
  				dev->search_id = rn;
  			}
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1024
  			desc_bit = last_zero;
c30c9b151   David Fries   W1: fix deadlocks...
1025
  			cb(dev, rn);
6b7298618   Evgeniy Polyakov   [PATCH] w1: Added...
1026
  		}
a16130569   David Fries   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   David Fries   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   David Fries   w1: increase w1_m...
1037
  			dev_info(&dev->dev, "%s: max_slave_count %d reached, "
3c6955e5a   David Fries   w1: continue slav...
1038
1039
  				"will continue next search.
  ", __func__,
a16130569   David Fries   w1: increase w1_m...
1040
1041
1042
  				dev->max_slave_count);
  			set_bit(W1_WARN_MAX_COUNT, &dev->flags);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043
1044
  	}
  }
963bb1010   David Fries   w1: have netlink ...
1045
1046
  void w1_search_process_cb(struct w1_master *dev, u8 search_type,
  	w1_slave_found_callback cb)
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1047
1048
  {
  	struct w1_slave *sl, *sln;
9fcbbac5d   David Fries   w1: process w1 ne...
1049
  	mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1050
  	list_for_each_entry(sl, &dev->slist, w1_slave_entry)
bb6709379   Michal Nazarewicz   drivers: w1: make...
1051
  		clear_bit(W1_SLAVE_ACTIVE, &sl->flags);
9fcbbac5d   David Fries   w1: process w1 ne...
1052
  	mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1053

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

9fcbbac5d   David Fries   w1: process w1 ne...
1056
  	mutex_lock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1057
  	list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
9fcbbac5d   David Fries   w1: process w1 ne...
1058
1059
  		if (!test_bit(W1_SLAVE_ACTIVE, &sl->flags) && !--sl->ttl) {
  			mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1060
  			w1_slave_detach(sl);
9fcbbac5d   David Fries   w1: process w1 ne...
1061
1062
  			mutex_lock(&dev->list_mutex);
  		}
bb6709379   Michal Nazarewicz   drivers: w1: make...
1063
  		else if (test_bit(W1_SLAVE_ACTIVE, &sl->flags))
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1064
1065
  			sl->ttl = dev->slave_ttl;
  	}
9fcbbac5d   David Fries   w1: process w1 ne...
1066
  	mutex_unlock(&dev->list_mutex);
12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1067
1068
1069
1070
  
  	if (dev->search_count > 0)
  		dev->search_count--;
  }
963bb1010   David Fries   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   David Fries   w1: format for Do...
1075
1076
1077
1078
  /**
   * w1_process_callbacks() - execute each dev->async_list callback entry
   * @dev: w1_master device
   *
a0f104644   Alexey Khoroshilov   w1: do not unlock...
1079
1080
   * The w1 master list_mutex must be held.
   *
b3be177a1   David Fries   w1: format for Do...
1081
1082
   * Return: 1 if there were commands to executed 0 otherwise
   */
9fcbbac5d   David Fries   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   Linus Torvalds   Linux-2.6.12-rc2
1102
1103
1104
  int w1_process(void *data)
  {
  	struct w1_master *dev = (struct w1_master *) data;
3c52e4e62   David Fries   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   Dmitry Khromov   w1: introduce an ...
1108
1109
  	const unsigned long jtime =
  	  usecs_to_jiffies(w1_timeout * 1000000 + w1_timeout_us);
9fcbbac5d   David Fries   w1: process w1 ne...
1110
1111
  	/* remainder if it woke up early */
  	unsigned long jremain = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112

9fcbbac5d   David Fries   w1: process w1 ne...
1113
1114
1115
  	for (;;) {
  
  		if (!jremain && dev->search_count) {
01e14d6db   David Fries   W1: don't delay s...
1116
1117
1118
1119
  			mutex_lock(&dev->mutex);
  			w1_search_process(dev, W1_SEARCH);
  			mutex_unlock(&dev->mutex);
  		}
9fcbbac5d   David Fries   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   David Fries   W1: w1_process, b...
1131
  		__set_current_state(TASK_INTERRUPTIBLE);
9fcbbac5d   David Fries   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   David Fries   W1: w1_process, b...
1136
1137
1138
1139
  		if (kthread_should_stop())
  			break;
  
  		/* Only sleep when the search is active. */
9fcbbac5d   David Fries   w1: process w1 ne...
1140
1141
1142
1143
1144
  		if (dev->search_count) {
  			if (!jremain)
  				jremain = jtime;
  			jremain = schedule_timeout(jremain);
  		}
3c52e4e62   David Fries   W1: w1_process, b...
1145
1146
  		else
  			schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
1148
1149
  	}
  
  	atomic_dec(&dev->refcnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1150
1151
1152
  
  	return 0;
  }
73a98fce8   Peter Huewe   w1: add __init/__...
1153
  static int __init w1_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1154
1155
  {
  	int retval;
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1156
1157
  	pr_info("Driver for 1-wire Dallas network protocol.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1159
  	w1_init_netlink();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1160
1161
  	retval = bus_register(&w1_bus_type);
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1162
1163
  		pr_err("Failed to register bus. err=%d.
  ", retval);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
  		goto err_out_exit_init;
  	}
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1166
  	retval = driver_register(&w1_master_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1168
1169
  		pr_err("Failed to register master driver. err=%d.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
  			retval);
  		goto err_out_bus_unregister;
  	}
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1173
1174
  	retval = driver_register(&w1_slave_driver);
  	if (retval) {
fdc9167a7   Fjodor Schelichow   w1: use pr_* inst...
1175
1176
  		pr_err("Failed to register slave driver. err=%d.
  ",
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1177
1178
1179
  			retval);
  		goto err_out_master_unregister;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1180
  	return 0;
c30c9b151   David Fries   W1: fix deadlocks...
1181
1182
  #if 0
  /* For undoing the slave register if there was a step after it. */
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1183
1184
  err_out_slave_unregister:
  	driver_unregister(&w1_slave_driver);
c30c9b151   David Fries   W1: fix deadlocks...
1185
  #endif
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1186
1187
1188
  
  err_out_master_unregister:
  	driver_unregister(&w1_master_driver);
1da177e4c   Linus Torvalds   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   Peter Huewe   w1: add __init/__...
1196
  static void __exit w1_fini(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197
1198
  {
  	struct w1_master *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1199

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

12003375a   Evgeniy Polyakov   [PATCH] w1: Users...
1204
  	w1_fini_netlink();
7f772ed8d   Evgeniy Polyakov   [PATCH] w1: hotpl...
1205
1206
  	driver_unregister(&w1_slave_driver);
  	driver_unregister(&w1_master_driver);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1207
1208
1209
1210
1211
  	bus_unregister(&w1_bus_type);
  }
  
  module_init(w1_init);
  module_exit(w1_fini);
50fa2951b   Andrew F. Davis   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");