This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / w1 / w1_family.c
1 /*
2  *      w1_family.c
3  *
4  * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
5  * 
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */
21
22 #include <linux/spinlock.h>
23 #include <linux/list.h>
24
25 #include "w1_family.h"
26
27 spinlock_t w1_flock = SPIN_LOCK_UNLOCKED;
28 static LIST_HEAD(w1_families);
29
30 int w1_register_family(struct w1_family *newf)
31 {
32         struct list_head *ent, *n;
33         struct w1_family *f;
34         int ret = 0;
35
36         spin_lock(&w1_flock);
37         list_for_each_safe(ent, n, &w1_families) {
38                 f = list_entry(ent, struct w1_family, family_entry);
39
40                 if (f->fid == newf->fid) {
41                         ret = -EEXIST;
42                         break;
43                 }
44         }
45
46         if (!ret) {
47                 atomic_set(&newf->refcnt, 0);
48                 newf->need_exit = 0;
49                 list_add_tail(&newf->family_entry, &w1_families);
50         }
51
52         spin_unlock(&w1_flock);
53
54         return ret;
55 }
56
57 void w1_unregister_family(struct w1_family *fent)
58 {
59         struct list_head *ent, *n;
60         struct w1_family *f;
61
62         spin_lock(&w1_flock);
63         list_for_each_safe(ent, n, &w1_families) {
64                 f = list_entry(ent, struct w1_family, family_entry);
65
66                 if (f->fid == fent->fid) {
67                         list_del(&fent->family_entry);
68                         break;
69                 }
70         }
71
72         fent->need_exit = 1;
73
74         spin_unlock(&w1_flock);
75
76         while (atomic_read(&fent->refcnt))
77                 schedule_timeout(10);
78 }
79
80 /*
81  * Should be called under w1_flock held.
82  */
83 struct w1_family * w1_family_registered(u8 fid)
84 {
85         struct list_head *ent, *n;
86         struct w1_family *f = NULL;
87         int ret = 0;
88
89         list_for_each_safe(ent, n, &w1_families) {
90                 f = list_entry(ent, struct w1_family, family_entry);
91
92                 if (f->fid == fid) {
93                         ret = 1;
94                         break;
95                 }
96         }
97
98         return (ret) ? f : NULL;
99 }
100
101 void w1_family_put(struct w1_family *f)
102 {
103         spin_lock(&w1_flock);
104         __w1_family_put(f);
105         spin_unlock(&w1_flock);
106 }
107
108 void __w1_family_put(struct w1_family *f)
109 {
110         if (atomic_dec_and_test(&f->refcnt))
111                 f->need_exit = 1;
112 }
113
114 void w1_family_get(struct w1_family *f)
115 {
116         spin_lock(&w1_flock);
117         __w1_family_get(f);
118         spin_unlock(&w1_flock);
119
120 }
121
122 void __w1_family_get(struct w1_family *f)
123 {
124         atomic_inc(&f->refcnt);
125 }
126
127 EXPORT_SYMBOL(w1_family_get);
128 EXPORT_SYMBOL(w1_family_put);
129 EXPORT_SYMBOL(__w1_family_get);
130 EXPORT_SYMBOL(__w1_family_put);
131 EXPORT_SYMBOL(w1_family_registered);
132 EXPORT_SYMBOL(w1_unregister_family);
133 EXPORT_SYMBOL(w1_register_family);