aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pvrusb2/pvrusb2-i2c-track.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-i2c-track.c')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-track.c503
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 d0682c13b02..00000000000
--- 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
40static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
41 unsigned int detail,
42 char *buf,unsigned int maxlen);
43
44static 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
57int 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
81int 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
100static 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
111void 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. */
126void 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
258int 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
303static 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
367unsigned 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
388void 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
415static 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
424void 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. */
459void 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
480void 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
489void 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 */