VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / media / dvb / dvb-core / dvb_i2c.c
1 /*
2  * dvb_i2c.h: simplified i2c interface for DVB adapters to get rid of i2c-core.c
3  *
4  * Copyright (C) 2002 Holger Waechtler for convergence integrated media GmbH
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
20  */
21
22 #include <linux/errno.h>
23 #include <linux/slab.h>
24 #include <linux/list.h>
25 #include <linux/module.h>
26 #include <asm/semaphore.h>
27
28 #include "dvb_i2c.h"
29 #include "dvb_functions.h"
30
31
32 struct dvb_i2c_device {
33         struct list_head list_head;
34         struct module *owner;
35         int (*attach) (struct dvb_i2c_bus *i2c, void **data);
36         void (*detach) (struct dvb_i2c_bus *i2c, void *data);
37         void *data;
38 };
39
40 LIST_HEAD(dvb_i2c_buslist);
41 LIST_HEAD(dvb_i2c_devicelist);
42
43 DECLARE_MUTEX(dvb_i2c_mutex);
44
45 static int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
46 {
47         struct dvb_i2c_device *client;
48
49         if (!(client = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL)))
50                 return -ENOMEM;
51
52         client->detach = dev->detach;
53         client->owner = dev->owner;
54         client->data = dev->data;
55
56         INIT_LIST_HEAD(&client->list_head);
57
58         list_add_tail (&client->list_head, &i2c->client_list);
59
60         return 0;
61 }
62
63
64 static void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
65 {
66         if (dev->owner) {
67                 if (!try_module_get(dev->owner))
68                         return;
69         }
70
71         if (dev->attach (i2c, &dev->data) == 0) {
72                 register_i2c_client (i2c, dev);
73         } else {
74                 if (dev->owner)
75                         module_put (dev->owner);
76         }
77 }
78
79
80 static void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
81 {
82         dev->detach (i2c, dev->data);
83
84         if (dev->owner)
85                 module_put (dev->owner);
86 }
87
88
89 static void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
90                                      struct dvb_i2c_bus *i2c)
91 {
92         struct list_head *entry, *n;
93
94         list_for_each_safe (entry, n, &i2c->client_list) {
95                 struct dvb_i2c_device *client;
96
97                 client = list_entry (entry, struct dvb_i2c_device, list_head);
98
99                 if (client->detach == dev->detach) {
100                         list_del (entry);
101                         detach_device (i2c, dev);
102                 }
103         }
104 }
105
106
107 static void unregister_i2c_client_from_all_busses (struct dvb_i2c_device *dev)
108 {
109         struct list_head *entry, *n;
110
111         list_for_each_safe (entry, n, &dvb_i2c_buslist) {
112                 struct dvb_i2c_bus *i2c;
113
114                 i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
115
116                 unregister_i2c_client_from_bus (dev, i2c);
117         }
118 }
119
120
121 static void unregister_all_clients_from_bus (struct dvb_i2c_bus *i2c)
122 {
123         struct list_head *entry, *n;
124
125         list_for_each_safe (entry, n, &(i2c->client_list)) {
126                 struct dvb_i2c_device *dev;
127
128                 dev = list_entry (entry, struct dvb_i2c_device, list_head);
129
130                 unregister_i2c_client_from_bus (dev, i2c);
131         }
132 }
133
134
135 static void probe_device_on_all_busses (struct dvb_i2c_device *dev)
136 {
137         struct list_head *entry;
138
139         list_for_each (entry, &dvb_i2c_buslist) {
140                 struct dvb_i2c_bus *i2c;
141
142                 i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
143
144                 try_attach_device (i2c, dev);
145         }
146 }
147
148
149 static void probe_devices_on_bus (struct dvb_i2c_bus *i2c)
150 {
151         struct list_head *entry;
152
153         list_for_each (entry, &dvb_i2c_devicelist) {
154                 struct dvb_i2c_device *dev;
155
156                 dev = list_entry (entry, struct dvb_i2c_device, list_head);
157
158                 try_attach_device (i2c, dev);
159         }
160 }
161
162
163 static struct dvb_i2c_bus* dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
164                                                    const struct i2c_msg msgs[],
165                                                    int num),
166                                       struct dvb_adapter *adapter,
167                                       int id)
168 {
169         struct list_head *entry;
170
171         list_for_each (entry, &dvb_i2c_buslist) {
172                 struct dvb_i2c_bus *i2c;
173
174                 i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
175
176                 if (i2c->xfer == xfer && i2c->adapter == adapter && i2c->id == id)
177                         return i2c;
178         }
179
180         return NULL;
181 }
182
183
184 struct dvb_i2c_bus*
185 dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
186                                    const struct i2c_msg *msgs, int num),
187                       void *data, struct dvb_adapter *adapter, int id)
188 {
189         struct dvb_i2c_bus *i2c;
190
191         if (down_interruptible (&dvb_i2c_mutex))
192                 return NULL;
193
194         if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL))) {
195                 up (&dvb_i2c_mutex);
196                 return NULL;
197         }
198
199         INIT_LIST_HEAD(&i2c->list_head);
200         INIT_LIST_HEAD(&i2c->client_list);
201
202         i2c->xfer = xfer;
203         i2c->data = data;
204         i2c->adapter = adapter;
205         i2c->id = id;
206
207         probe_devices_on_bus (i2c);
208
209         list_add_tail (&i2c->list_head, &dvb_i2c_buslist);
210
211         up (&dvb_i2c_mutex);
212
213         return i2c;
214 }
215
216
217 void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
218                                           const struct i2c_msg msgs[], int num),
219                              struct dvb_adapter *adapter, int id)
220 {
221         struct dvb_i2c_bus *i2c;
222
223         down (&dvb_i2c_mutex);
224
225         if ((i2c = dvb_find_i2c_bus (xfer, adapter, id))) {
226                 unregister_all_clients_from_bus (i2c);
227                 list_del (&i2c->list_head);
228                 kfree (i2c);
229         }
230
231         up (&dvb_i2c_mutex);
232 }
233
234
235 int dvb_register_i2c_device (struct module *owner,
236                              int (*attach) (struct dvb_i2c_bus *i2c, void **data),
237                              void (*detach) (struct dvb_i2c_bus *i2c, void *data))
238 {
239         struct dvb_i2c_device *entry;
240
241         if (down_interruptible (&dvb_i2c_mutex))
242                 return -ERESTARTSYS;
243
244         if (!(entry = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL))) {
245                 up(&dvb_i2c_mutex);
246                 return -ENOMEM;
247         }
248
249         entry->owner = owner;
250         entry->attach = attach;
251         entry->detach = detach;
252
253         INIT_LIST_HEAD(&entry->list_head);
254
255         probe_device_on_all_busses (entry);
256
257         list_add_tail (&entry->list_head, &dvb_i2c_devicelist);
258
259         up (&dvb_i2c_mutex);
260
261         return 0;
262 }
263
264
265 int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data))
266 {
267         struct list_head *entry, *n;
268
269         down (&dvb_i2c_mutex);
270
271         list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
272                 struct dvb_i2c_device *dev;
273
274                 dev = list_entry (entry, struct dvb_i2c_device, list_head);
275
276                 if (dev->attach == attach) {
277                         list_del (entry);
278                         unregister_i2c_client_from_all_busses (dev);
279                         kfree (entry);
280                         up (&dvb_i2c_mutex);
281                         return 0;
282                 }
283         }
284
285         up (&dvb_i2c_mutex);
286
287         return -EINVAL;
288 }
289
290