ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[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                 return NULL;
196
197         INIT_LIST_HEAD(&i2c->list_head);
198         INIT_LIST_HEAD(&i2c->client_list);
199
200         i2c->xfer = xfer;
201         i2c->data = data;
202         i2c->adapter = adapter;
203         i2c->id = id;
204
205         probe_devices_on_bus (i2c);
206
207         list_add_tail (&i2c->list_head, &dvb_i2c_buslist);
208
209         up (&dvb_i2c_mutex);
210
211         return i2c;
212 }
213
214
215 void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
216                                           const struct i2c_msg msgs[], int num),
217                              struct dvb_adapter *adapter, int id)
218 {
219         struct dvb_i2c_bus *i2c;
220
221         down (&dvb_i2c_mutex);
222
223         if ((i2c = dvb_find_i2c_bus (xfer, adapter, id))) {
224                 unregister_all_clients_from_bus (i2c);
225                 list_del (&i2c->list_head);
226                 kfree (i2c);
227         }
228
229         up (&dvb_i2c_mutex);
230 }
231
232
233 int dvb_register_i2c_device (struct module *owner,
234                              int (*attach) (struct dvb_i2c_bus *i2c, void **data),
235                              void (*detach) (struct dvb_i2c_bus *i2c, void *data))
236 {
237         struct dvb_i2c_device *entry;
238
239         if (down_interruptible (&dvb_i2c_mutex))
240                 return -ERESTARTSYS;
241
242         if (!(entry = kmalloc (sizeof (struct dvb_i2c_device), GFP_KERNEL)))
243                 return -ENOMEM;
244
245         entry->owner = owner;
246         entry->attach = attach;
247         entry->detach = detach;
248
249         INIT_LIST_HEAD(&entry->list_head);
250
251         probe_device_on_all_busses (entry);
252
253         list_add_tail (&entry->list_head, &dvb_i2c_devicelist);
254
255         up (&dvb_i2c_mutex);
256
257         return 0;
258 }
259
260
261 int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c, void **data))
262 {
263         struct list_head *entry, *n;
264
265         down (&dvb_i2c_mutex);
266
267         list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
268                 struct dvb_i2c_device *dev;
269
270                 dev = list_entry (entry, struct dvb_i2c_device, list_head);
271
272                 if (dev->attach == attach) {
273                         list_del (entry);
274                         unregister_i2c_client_from_all_busses (dev);
275                         kfree (entry);
276                         up (&dvb_i2c_mutex);
277                         return 0;
278                 }
279         }
280
281         up (&dvb_i2c_mutex);
282
283         return -EINVAL;
284 }
285
286