diff options
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-i2c-track.c')
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-i2c-track.c | 503 |
1 files changed, 0 insertions, 503 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c deleted file mode 100644 index d0682c13b02a..000000000000 --- a/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c +++ /dev/null | |||
@@ -1,503 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * | ||
4 | * Copyright (C) 2005 Mike Isely <isely@pobox.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include "pvrusb2-i2c-track.h" | ||
22 | #include "pvrusb2-hdw-internal.h" | ||
23 | #include "pvrusb2-debug.h" | ||
24 | #include "pvrusb2-fx2-cmd.h" | ||
25 | #include "pvrusb2.h" | ||
26 | |||
27 | #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__) | ||
28 | |||
29 | |||
30 | /* | ||
31 | |||
32 | This module implements the foundation of a rather large architecture for | ||
33 | tracking state in all the various V4L I2C modules. This is obsolete with | ||
34 | kernels later than roughly 2.6.24, but it is still present in the | ||
35 | standalone pvrusb2 driver to allow continued operation with older | ||
36 | kernel. | ||
37 | |||
38 | */ | ||
39 | |||
40 | static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp, | ||
41 | unsigned int detail, | ||
42 | char *buf,unsigned int maxlen); | ||
43 | |||
44 | static int pvr2_i2c_core_singleton(struct i2c_client *cp, | ||
45 | unsigned int cmd,void *arg) | ||
46 | { | ||
47 | int stat; | ||
48 | if (!cp) return -EINVAL; | ||
49 | if (!(cp->driver)) return -EINVAL; | ||
50 | if (!(cp->driver->command)) return -EINVAL; | ||
51 | if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN; | ||
52 | stat = cp->driver->command(cp,cmd,arg); | ||
53 | module_put(cp->driver->driver.owner); | ||
54 | return stat; | ||
55 | } | ||
56 | |||
57 | int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg) | ||
58 | { | ||
59 | int stat; | ||
60 | if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) { | ||
61 | char buf[100]; | ||
62 | unsigned int cnt; | ||
63 | cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG, | ||
64 | buf,sizeof(buf)); | ||
65 | pvr2_trace(PVR2_TRACE_I2C_CMD, | ||
66 | "i2c COMMAND (code=%u 0x%x) to %.*s", | ||
67 | cmd,cmd,cnt,buf); | ||
68 | } | ||
69 | stat = pvr2_i2c_core_singleton(cp->client,cmd,arg); | ||
70 | if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) { | ||
71 | char buf[100]; | ||
72 | unsigned int cnt; | ||
73 | cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG, | ||
74 | buf,sizeof(buf)); | ||
75 | pvr2_trace(PVR2_TRACE_I2C_CMD, | ||
76 | "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat); | ||
77 | } | ||
78 | return stat; | ||
79 | } | ||
80 | |||
81 | int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg) | ||
82 | { | ||
83 | struct pvr2_i2c_client *cp, *ncp; | ||
84 | int stat = -EINVAL; | ||
85 | |||
86 | if (!hdw) return stat; | ||
87 | |||
88 | mutex_lock(&hdw->i2c_list_lock); | ||
89 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { | ||
90 | if (!cp->recv_enable) continue; | ||
91 | mutex_unlock(&hdw->i2c_list_lock); | ||
92 | stat = pvr2_i2c_client_cmd(cp,cmd,arg); | ||
93 | mutex_lock(&hdw->i2c_list_lock); | ||
94 | } | ||
95 | mutex_unlock(&hdw->i2c_list_lock); | ||
96 | return stat; | ||
97 | } | ||
98 | |||
99 | |||
100 | static int handler_check(struct pvr2_i2c_client *cp) | ||
101 | { | ||
102 | struct pvr2_i2c_handler *hp = cp->handler; | ||
103 | if (!hp) return 0; | ||
104 | if (!hp->func_table->check) return 0; | ||
105 | return hp->func_table->check(hp->func_data) != 0; | ||
106 | } | ||
107 | |||
108 | #define BUFSIZE 500 | ||
109 | |||
110 | |||
111 | void pvr2_i2c_core_status_poll(struct pvr2_hdw *hdw) | ||
112 | { | ||
113 | struct pvr2_i2c_client *cp; | ||
114 | mutex_lock(&hdw->i2c_list_lock); do { | ||
115 | list_for_each_entry(cp, &hdw->i2c_clients, list) { | ||
116 | if (!cp->detected_flag) continue; | ||
117 | if (!cp->status_poll) continue; | ||
118 | cp->status_poll(cp); | ||
119 | } | ||
120 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
121 | } | ||
122 | |||
123 | |||
124 | /* Issue various I2C operations to bring chip-level drivers into sync with | ||
125 | state stored in this driver. */ | ||
126 | void pvr2_i2c_core_sync(struct pvr2_hdw *hdw) | ||
127 | { | ||
128 | unsigned long msk; | ||
129 | unsigned int idx; | ||
130 | struct pvr2_i2c_client *cp, *ncp; | ||
131 | |||
132 | if (!hdw->i2c_linked) return; | ||
133 | if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) { | ||
134 | return; | ||
135 | } | ||
136 | mutex_lock(&hdw->i2c_list_lock); do { | ||
137 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN"); | ||
138 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) { | ||
139 | /* One or more I2C clients have attached since we | ||
140 | last synced. So scan the list and identify the | ||
141 | new clients. */ | ||
142 | char *buf; | ||
143 | unsigned int cnt; | ||
144 | unsigned long amask = 0; | ||
145 | buf = kmalloc(BUFSIZE,GFP_KERNEL); | ||
146 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT"); | ||
147 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT; | ||
148 | list_for_each_entry(cp, &hdw->i2c_clients, list) { | ||
149 | if (!cp->detected_flag) { | ||
150 | cp->ctl_mask = 0; | ||
151 | pvr2_i2c_probe(hdw,cp); | ||
152 | cp->detected_flag = !0; | ||
153 | msk = cp->ctl_mask; | ||
154 | cnt = 0; | ||
155 | if (buf) { | ||
156 | cnt = pvr2_i2c_client_describe( | ||
157 | cp, | ||
158 | PVR2_I2C_DETAIL_ALL, | ||
159 | buf,BUFSIZE); | ||
160 | } | ||
161 | trace_i2c("Probed: %.*s",cnt,buf); | ||
162 | if (handler_check(cp)) { | ||
163 | hdw->i2c_pend_types |= | ||
164 | PVR2_I2C_PEND_CLIENT; | ||
165 | } | ||
166 | cp->pend_mask = msk; | ||
167 | hdw->i2c_pend_mask |= msk; | ||
168 | hdw->i2c_pend_types |= | ||
169 | PVR2_I2C_PEND_REFRESH; | ||
170 | } | ||
171 | amask |= cp->ctl_mask; | ||
172 | } | ||
173 | hdw->i2c_active_mask = amask; | ||
174 | if (buf) kfree(buf); | ||
175 | } | ||
176 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) { | ||
177 | /* Need to do one or more global updates. Arrange | ||
178 | for this to happen. */ | ||
179 | unsigned long m2; | ||
180 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
181 | "i2c: PEND_STALE (0x%lx)", | ||
182 | hdw->i2c_stale_mask); | ||
183 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE; | ||
184 | list_for_each_entry(cp, &hdw->i2c_clients, list) { | ||
185 | m2 = hdw->i2c_stale_mask; | ||
186 | m2 &= cp->ctl_mask; | ||
187 | m2 &= ~cp->pend_mask; | ||
188 | if (m2) { | ||
189 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
190 | "i2c: cp=%p setting 0x%lx", | ||
191 | cp,m2); | ||
192 | cp->pend_mask |= m2; | ||
193 | } | ||
194 | } | ||
195 | hdw->i2c_pend_mask |= hdw->i2c_stale_mask; | ||
196 | hdw->i2c_stale_mask = 0; | ||
197 | hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH; | ||
198 | } | ||
199 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) { | ||
200 | /* One or more client handlers are asking for an | ||
201 | update. Run through the list of known clients | ||
202 | and update each one. */ | ||
203 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT"); | ||
204 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT; | ||
205 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, | ||
206 | list) { | ||
207 | if (!cp->handler) continue; | ||
208 | if (!cp->handler->func_table->update) continue; | ||
209 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
210 | "i2c: cp=%p update",cp); | ||
211 | mutex_unlock(&hdw->i2c_list_lock); | ||
212 | cp->handler->func_table->update( | ||
213 | cp->handler->func_data); | ||
214 | mutex_lock(&hdw->i2c_list_lock); | ||
215 | /* If client's update function set some | ||
216 | additional pending bits, account for that | ||
217 | here. */ | ||
218 | if (cp->pend_mask & ~hdw->i2c_pend_mask) { | ||
219 | hdw->i2c_pend_mask |= cp->pend_mask; | ||
220 | hdw->i2c_pend_types |= | ||
221 | PVR2_I2C_PEND_REFRESH; | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) { | ||
226 | const struct pvr2_i2c_op *opf; | ||
227 | unsigned long pm; | ||
228 | /* Some actual updates are pending. Walk through | ||
229 | each update type and perform it. */ | ||
230 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH" | ||
231 | " (0x%lx)",hdw->i2c_pend_mask); | ||
232 | hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH; | ||
233 | pm = hdw->i2c_pend_mask; | ||
234 | hdw->i2c_pend_mask = 0; | ||
235 | for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { | ||
236 | if (!(pm & msk)) continue; | ||
237 | pm &= ~msk; | ||
238 | list_for_each_entry(cp, &hdw->i2c_clients, | ||
239 | list) { | ||
240 | if (cp->pend_mask & msk) { | ||
241 | cp->pend_mask &= ~msk; | ||
242 | cp->recv_enable = !0; | ||
243 | } else { | ||
244 | cp->recv_enable = 0; | ||
245 | } | ||
246 | } | ||
247 | opf = pvr2_i2c_get_op(idx); | ||
248 | if (!opf) continue; | ||
249 | mutex_unlock(&hdw->i2c_list_lock); | ||
250 | opf->update(hdw); | ||
251 | mutex_lock(&hdw->i2c_list_lock); | ||
252 | } | ||
253 | } | ||
254 | pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END"); | ||
255 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
256 | } | ||
257 | |||
258 | int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw) | ||
259 | { | ||
260 | unsigned long msk,sm,pm; | ||
261 | unsigned int idx; | ||
262 | const struct pvr2_i2c_op *opf; | ||
263 | struct pvr2_i2c_client *cp; | ||
264 | unsigned int pt = 0; | ||
265 | |||
266 | pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN"); | ||
267 | |||
268 | pm = hdw->i2c_active_mask; | ||
269 | sm = 0; | ||
270 | for (idx = 0, msk = 1; pm; idx++, msk <<= 1) { | ||
271 | if (!(msk & pm)) continue; | ||
272 | pm &= ~msk; | ||
273 | opf = pvr2_i2c_get_op(idx); | ||
274 | if (!(opf && opf->check)) continue; | ||
275 | if (opf->check(hdw)) { | ||
276 | sm |= msk; | ||
277 | } | ||
278 | } | ||
279 | if (sm) pt |= PVR2_I2C_PEND_STALE; | ||
280 | |||
281 | list_for_each_entry(cp, &hdw->i2c_clients, list) | ||
282 | if (handler_check(cp)) | ||
283 | pt |= PVR2_I2C_PEND_CLIENT; | ||
284 | |||
285 | if (pt) { | ||
286 | mutex_lock(&hdw->i2c_list_lock); do { | ||
287 | hdw->i2c_pend_types |= pt; | ||
288 | hdw->i2c_stale_mask |= sm; | ||
289 | hdw->i2c_pend_mask |= hdw->i2c_stale_mask; | ||
290 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
291 | } | ||
292 | |||
293 | pvr2_trace(PVR2_TRACE_I2C_CORE, | ||
294 | "i2c: types=0x%x stale=0x%lx pend=0x%lx", | ||
295 | hdw->i2c_pend_types, | ||
296 | hdw->i2c_stale_mask, | ||
297 | hdw->i2c_pend_mask); | ||
298 | pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END"); | ||
299 | |||
300 | return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0; | ||
301 | } | ||
302 | |||
303 | static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp, | ||
304 | unsigned int detail, | ||
305 | char *buf,unsigned int maxlen) | ||
306 | { | ||
307 | unsigned int ccnt,bcnt; | ||
308 | int spcfl = 0; | ||
309 | const struct pvr2_i2c_op *opf; | ||
310 | |||
311 | ccnt = 0; | ||
312 | if (detail & PVR2_I2C_DETAIL_DEBUG) { | ||
313 | bcnt = scnprintf(buf,maxlen, | ||
314 | "ctxt=%p ctl_mask=0x%lx", | ||
315 | cp,cp->ctl_mask); | ||
316 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
317 | spcfl = !0; | ||
318 | } | ||
319 | bcnt = scnprintf(buf,maxlen, | ||
320 | "%s%s @ 0x%x", | ||
321 | (spcfl ? " " : ""), | ||
322 | cp->client->name, | ||
323 | cp->client->addr); | ||
324 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
325 | if ((detail & PVR2_I2C_DETAIL_HANDLER) && | ||
326 | cp->handler && cp->handler->func_table->describe) { | ||
327 | bcnt = scnprintf(buf,maxlen," ("); | ||
328 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
329 | bcnt = cp->handler->func_table->describe( | ||
330 | cp->handler->func_data,buf,maxlen); | ||
331 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
332 | bcnt = scnprintf(buf,maxlen,")"); | ||
333 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
334 | } | ||
335 | if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) { | ||
336 | unsigned int idx; | ||
337 | unsigned long msk,sm; | ||
338 | |||
339 | bcnt = scnprintf(buf,maxlen," ["); | ||
340 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
341 | sm = 0; | ||
342 | spcfl = 0; | ||
343 | for (idx = 0, msk = 1; msk; idx++, msk <<= 1) { | ||
344 | if (!(cp->ctl_mask & msk)) continue; | ||
345 | opf = pvr2_i2c_get_op(idx); | ||
346 | if (opf) { | ||
347 | bcnt = scnprintf(buf,maxlen,"%s%s", | ||
348 | spcfl ? " " : "", | ||
349 | opf->name); | ||
350 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
351 | spcfl = !0; | ||
352 | } else { | ||
353 | sm |= msk; | ||
354 | } | ||
355 | } | ||
356 | if (sm) { | ||
357 | bcnt = scnprintf(buf,maxlen,"%s%lx", | ||
358 | idx != 0 ? " " : "",sm); | ||
359 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
360 | } | ||
361 | bcnt = scnprintf(buf,maxlen,"]"); | ||
362 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
363 | } | ||
364 | return ccnt; | ||
365 | } | ||
366 | |||
367 | unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw, | ||
368 | char *buf,unsigned int maxlen) | ||
369 | { | ||
370 | unsigned int ccnt,bcnt; | ||
371 | struct pvr2_i2c_client *cp; | ||
372 | ccnt = 0; | ||
373 | mutex_lock(&hdw->i2c_list_lock); do { | ||
374 | list_for_each_entry(cp, &hdw->i2c_clients, list) { | ||
375 | bcnt = pvr2_i2c_client_describe( | ||
376 | cp, | ||
377 | (PVR2_I2C_DETAIL_HANDLER| | ||
378 | PVR2_I2C_DETAIL_CTLMASK), | ||
379 | buf,maxlen); | ||
380 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
381 | bcnt = scnprintf(buf,maxlen,"\n"); | ||
382 | ccnt += bcnt; buf += bcnt; maxlen -= bcnt; | ||
383 | } | ||
384 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
385 | return ccnt; | ||
386 | } | ||
387 | |||
388 | void pvr2_i2c_track_attach_inform(struct i2c_client *client) | ||
389 | { | ||
390 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); | ||
391 | struct pvr2_i2c_client *cp; | ||
392 | int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL); | ||
393 | cp = kzalloc(sizeof(*cp),GFP_KERNEL); | ||
394 | trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]", | ||
395 | client->name, | ||
396 | client->addr,cp); | ||
397 | if (!cp) { | ||
398 | pvr2_trace(PVR2_TRACE_ERROR_LEGS, | ||
399 | "Unable to allocate tracking memory for incoming" | ||
400 | " i2c module; ignoring module. This is likely" | ||
401 | " going to be a problem."); | ||
402 | return; | ||
403 | } | ||
404 | cp->hdw = hdw; | ||
405 | INIT_LIST_HEAD(&cp->list); | ||
406 | cp->client = client; | ||
407 | mutex_lock(&hdw->i2c_list_lock); do { | ||
408 | hdw->cropcap_stale = !0; | ||
409 | list_add_tail(&cp->list,&hdw->i2c_clients); | ||
410 | hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; | ||
411 | } while (0); mutex_unlock(&hdw->i2c_list_lock); | ||
412 | if (fl) queue_work(hdw->workqueue,&hdw->worki2csync); | ||
413 | } | ||
414 | |||
415 | static void pvr2_i2c_client_disconnect(struct pvr2_i2c_client *cp) | ||
416 | { | ||
417 | if (cp->handler && cp->handler->func_table->detach) { | ||
418 | cp->handler->func_table->detach(cp->handler->func_data); | ||
419 | } | ||
420 | list_del(&cp->list); | ||
421 | kfree(cp); | ||
422 | } | ||
423 | |||
424 | void pvr2_i2c_track_detach_inform(struct i2c_client *client) | ||
425 | { | ||
426 | struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data); | ||
427 | struct pvr2_i2c_client *cp, *ncp; | ||
428 | unsigned long amask = 0; | ||
429 | int foundfl = 0; | ||
430 | mutex_lock(&hdw->i2c_list_lock); | ||
431 | hdw->cropcap_stale = !0; | ||
432 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { | ||
433 | if (cp->client == client) { | ||
434 | trace_i2c("pvr2_i2c_detach" | ||
435 | " [client=%s @ 0x%x ctxt=%p]", | ||
436 | client->name, | ||
437 | client->addr, cp); | ||
438 | pvr2_i2c_client_disconnect(cp); | ||
439 | foundfl = !0; | ||
440 | continue; | ||
441 | } | ||
442 | amask |= cp->ctl_mask; | ||
443 | } | ||
444 | hdw->i2c_active_mask = amask; | ||
445 | mutex_unlock(&hdw->i2c_list_lock); | ||
446 | if (!foundfl) { | ||
447 | trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]", | ||
448 | client->name, client->addr); | ||
449 | } | ||
450 | } | ||
451 | |||
452 | /* This function is used to remove an i2c client from our tracking | ||
453 | structure if the client happens to be the specified v4l2 sub-device. | ||
454 | The idea here is to ensure that sub-devices are not also tracked with | ||
455 | the old tracking mechanism - it's one or the other not both. This is | ||
456 | only for debugging. In a "real" environment, only one of these two | ||
457 | mechanisms should even be compiled in. But by enabling both we can | ||
458 | incrementally test control of each sub-device. */ | ||
459 | void pvr2_i2c_untrack_subdev(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) | ||
460 | { | ||
461 | struct i2c_client *client; | ||
462 | struct pvr2_i2c_client *cp, *ncp; | ||
463 | unsigned long amask = 0; | ||
464 | mutex_lock(&hdw->i2c_list_lock); | ||
465 | list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { | ||
466 | client = cp->client; | ||
467 | if (i2c_get_clientdata(client) == sd) { | ||
468 | trace_i2c("pvr2_i2c_detach (subdev active)" | ||
469 | " [client=%s @ 0x%x ctxt=%p]", | ||
470 | client->name, client->addr, cp); | ||
471 | pvr2_i2c_client_disconnect(cp); | ||
472 | continue; | ||
473 | } | ||
474 | amask |= cp->ctl_mask; | ||
475 | } | ||
476 | hdw->i2c_active_mask = amask; | ||
477 | mutex_unlock(&hdw->i2c_list_lock); | ||
478 | } | ||
479 | |||
480 | void pvr2_i2c_track_init(struct pvr2_hdw *hdw) | ||
481 | { | ||
482 | hdw->i2c_pend_mask = 0; | ||
483 | hdw->i2c_stale_mask = 0; | ||
484 | hdw->i2c_active_mask = 0; | ||
485 | INIT_LIST_HEAD(&hdw->i2c_clients); | ||
486 | mutex_init(&hdw->i2c_list_lock); | ||
487 | } | ||
488 | |||
489 | void pvr2_i2c_track_done(struct pvr2_hdw *hdw) | ||
490 | { | ||
491 | /* Empty for now */ | ||
492 | } | ||
493 | |||
494 | |||
495 | /* | ||
496 | Stuff for Emacs to see, in order to encourage consistent editing style: | ||
497 | *** Local Variables: *** | ||
498 | *** mode: c *** | ||
499 | *** fill-column: 75 *** | ||
500 | *** tab-width: 8 *** | ||
501 | *** c-basic-offset: 8 *** | ||
502 | *** End: *** | ||
503 | */ | ||