1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net> |
4 | */ |
5 | |
6 | #include <linux/spinlock.h> |
7 | #include <linux/list.h> |
8 | #include <linux/sched/signal.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/export.h> |
11 | |
12 | #include "w1_internal.h" |
13 | |
14 | DEFINE_SPINLOCK(w1_flock); |
15 | static LIST_HEAD(w1_families); |
16 | |
17 | /** |
18 | * w1_register_family() - register a device family driver |
19 | * @newf: family to register |
20 | */ |
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 | |
27 | spin_lock(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(v: &newf->refcnt, i: 0); |
39 | list_add_tail(new: &newf->family_entry, head: &w1_families); |
40 | } |
41 | spin_unlock(lock: &w1_flock); |
42 | |
43 | /* check default devices against the new set of drivers */ |
44 | w1_reconnect_slaves(f: newf, attach: 1); |
45 | |
46 | return ret; |
47 | } |
48 | EXPORT_SYMBOL(w1_register_family); |
49 | |
50 | /** |
51 | * w1_unregister_family() - unregister a device family driver |
52 | * @fent: family to unregister |
53 | */ |
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(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(entry: &fent->family_entry); |
65 | break; |
66 | } |
67 | } |
68 | spin_unlock(lock: &w1_flock); |
69 | |
70 | /* deatch devices using this family code */ |
71 | w1_reconnect_slaves(f: fent, attach: 0); |
72 | |
73 | while (atomic_read(v: &fent->refcnt)) { |
74 | pr_info("Waiting for family %u to become free: refcnt=%d.\n" , |
75 | fent->fid, atomic_read(&fent->refcnt)); |
76 | |
77 | if (msleep_interruptible(msecs: 1000)) |
78 | flush_signals(current); |
79 | } |
80 | } |
81 | EXPORT_SYMBOL(w1_unregister_family); |
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 | |
104 | static void __w1_family_put(struct w1_family *f) |
105 | { |
106 | atomic_dec(v: &f->refcnt); |
107 | } |
108 | |
109 | void w1_family_put(struct w1_family *f) |
110 | { |
111 | spin_lock(lock: &w1_flock); |
112 | __w1_family_put(f); |
113 | spin_unlock(lock: &w1_flock); |
114 | } |
115 | |
116 | #if 0 |
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); |
122 | } |
123 | #endif /* 0 */ |
124 | |
125 | void __w1_family_get(struct w1_family *f) |
126 | { |
127 | smp_mb__before_atomic(); |
128 | atomic_inc(v: &f->refcnt); |
129 | smp_mb__after_atomic(); |
130 | } |
131 | |