Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
a8018766 | 3 | * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> |
1da177e4 LT |
4 | */ |
5 | ||
6 | #include <linux/spinlock.h> | |
7 | #include <linux/list.h> | |
3f07c014 | 8 | #include <linux/sched/signal.h> |
1da177e4 | 9 | #include <linux/delay.h> |
9623932c | 10 | #include <linux/export.h> |
1da177e4 | 11 | |
de0d6dbd | 12 | #include "w1_internal.h" |
1da177e4 LT |
13 | |
14 | DEFINE_SPINLOCK(w1_flock); | |
15 | static LIST_HEAD(w1_families); | |
16 | ||
b3be177a DF |
17 | /** |
18 | * w1_register_family() - register a device family driver | |
19 | * @newf: family to register | |
20 | */ | |
1da177e4 LT |
21 | int w1_register_family(struct w1_family *newf) |
22 | { | |
23 | struct list_head *ent, *n; | |
24 | struct w1_family *f; | |
25 | int ret = 0; | |
26 | ||
1da177e4 LT |
27 | spin_lock(&w1_flock); |
28 | list_for_each_safe(ent, n, &w1_families) { | |
29 | f = list_entry(ent, struct w1_family, family_entry); | |
30 | ||
31 | if (f->fid == newf->fid) { | |
32 | ret = -EEXIST; | |
33 | break; | |
34 | } | |
35 | } | |
36 | ||
37 | if (!ret) { | |
38 | atomic_set(&newf->refcnt, 0); | |
1da177e4 LT |
39 | list_add_tail(&newf->family_entry, &w1_families); |
40 | } | |
1da177e4 LT |
41 | spin_unlock(&w1_flock); |
42 | ||
c30c9b15 DF |
43 | /* check default devices against the new set of drivers */ |
44 | w1_reconnect_slaves(newf, 1); | |
6adf87bd | 45 | |
1da177e4 LT |
46 | return ret; |
47 | } | |
50fa2951 | 48 | EXPORT_SYMBOL(w1_register_family); |
1da177e4 | 49 | |
b3be177a DF |
50 | /** |
51 | * w1_unregister_family() - unregister a device family driver | |
52 | * @fent: family to unregister | |
53 | */ | |
1da177e4 LT |
54 | void w1_unregister_family(struct w1_family *fent) |
55 | { | |
56 | struct list_head *ent, *n; | |
57 | struct w1_family *f; | |
58 | ||
59 | spin_lock(&w1_flock); | |
60 | list_for_each_safe(ent, n, &w1_families) { | |
61 | f = list_entry(ent, struct w1_family, family_entry); | |
62 | ||
63 | if (f->fid == fent->fid) { | |
64 | list_del(&fent->family_entry); | |
65 | break; | |
66 | } | |
67 | } | |
1da177e4 LT |
68 | spin_unlock(&w1_flock); |
69 | ||
c30c9b15 DF |
70 | /* deatch devices using this family code */ |
71 | w1_reconnect_slaves(fent, 0); | |
72 | ||
1da177e4 | 73 | while (atomic_read(&fent->refcnt)) { |
fdc9167a | 74 | pr_info("Waiting for family %u to become free: refcnt=%d.\n", |
1da177e4 LT |
75 | fent->fid, atomic_read(&fent->refcnt)); |
76 | ||
77 | if (msleep_interruptible(1000)) | |
78 | flush_signals(current); | |
79 | } | |
80 | } | |
50fa2951 | 81 | EXPORT_SYMBOL(w1_unregister_family); |
1da177e4 LT |
82 | |
83 | /* | |
84 | * Should be called under w1_flock held. | |
85 | */ | |
86 | struct w1_family * w1_family_registered(u8 fid) | |
87 | { | |
88 | struct list_head *ent, *n; | |
89 | struct w1_family *f = NULL; | |
90 | int ret = 0; | |
91 | ||
92 | list_for_each_safe(ent, n, &w1_families) { | |
93 | f = list_entry(ent, struct w1_family, family_entry); | |
94 | ||
95 | if (f->fid == fid) { | |
96 | ret = 1; | |
97 | break; | |
98 | } | |
99 | } | |
100 | ||
101 | return (ret) ? f : NULL; | |
102 | } | |
103 | ||
70d484bf EP |
104 | static void __w1_family_put(struct w1_family *f) |
105 | { | |
fe3cb823 | 106 | atomic_dec(&f->refcnt); |
70d484bf EP |
107 | } |
108 | ||
1da177e4 LT |
109 | void w1_family_put(struct w1_family *f) |
110 | { | |
111 | spin_lock(&w1_flock); | |
112 | __w1_family_put(f); | |
113 | spin_unlock(&w1_flock); | |
114 | } | |
115 | ||
70d484bf | 116 | #if 0 |
1da177e4 LT |
117 | void w1_family_get(struct w1_family *f) |
118 | { | |
119 | spin_lock(&w1_flock); | |
120 | __w1_family_get(f); | |
121 | spin_unlock(&w1_flock); | |
1da177e4 | 122 | } |
70d484bf | 123 | #endif /* 0 */ |
1da177e4 LT |
124 | |
125 | void __w1_family_get(struct w1_family *f) | |
126 | { | |
4e857c58 | 127 | smp_mb__before_atomic(); |
1da177e4 | 128 | atomic_inc(&f->refcnt); |
4e857c58 | 129 | smp_mb__after_atomic(); |
1da177e4 | 130 | } |