V4L/DVB (11159): pvrusb2: Providing means to stop tracking an old i2c module
[deliverable/linux.git] / drivers / media / video / pvrusb2 / pvrusb2-i2c-track.c
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 struct v4l2_tuner *vtp = &hdw->tuner_signal_info;
116 memset(vtp,0,sizeof(*vtp));
117 list_for_each_entry(cp, &hdw->i2c_clients, list) {
118 if (!cp->detected_flag) continue;
119 if (!cp->status_poll) continue;
120 cp->status_poll(cp);
121 }
122 hdw->tuner_signal_stale = 0;
123 pvr2_trace(PVR2_TRACE_CHIPS,"i2c status poll"
124 " type=%u strength=%u audio=0x%x cap=0x%x"
125 " low=%u hi=%u",
126 vtp->type,
127 vtp->signal,vtp->rxsubchans,vtp->capability,
128 vtp->rangelow,vtp->rangehigh);
129 } while (0); mutex_unlock(&hdw->i2c_list_lock);
130 }
131
132
133 /* Issue various I2C operations to bring chip-level drivers into sync with
134 state stored in this driver. */
135 void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
136 {
137 unsigned long msk;
138 unsigned int idx;
139 struct pvr2_i2c_client *cp, *ncp;
140
141 if (!hdw->i2c_linked) return;
142 if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
143 return;
144 }
145 mutex_lock(&hdw->i2c_list_lock); do {
146 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
147 if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
148 /* One or more I2C clients have attached since we
149 last synced. So scan the list and identify the
150 new clients. */
151 char *buf;
152 unsigned int cnt;
153 unsigned long amask = 0;
154 buf = kmalloc(BUFSIZE,GFP_KERNEL);
155 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
156 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
157 list_for_each_entry(cp, &hdw->i2c_clients, list) {
158 if (!cp->detected_flag) {
159 cp->ctl_mask = 0;
160 pvr2_i2c_probe(hdw,cp);
161 cp->detected_flag = !0;
162 msk = cp->ctl_mask;
163 cnt = 0;
164 if (buf) {
165 cnt = pvr2_i2c_client_describe(
166 cp,
167 PVR2_I2C_DETAIL_ALL,
168 buf,BUFSIZE);
169 }
170 trace_i2c("Probed: %.*s",cnt,buf);
171 if (handler_check(cp)) {
172 hdw->i2c_pend_types |=
173 PVR2_I2C_PEND_CLIENT;
174 }
175 cp->pend_mask = msk;
176 hdw->i2c_pend_mask |= msk;
177 hdw->i2c_pend_types |=
178 PVR2_I2C_PEND_REFRESH;
179 }
180 amask |= cp->ctl_mask;
181 }
182 hdw->i2c_active_mask = amask;
183 if (buf) kfree(buf);
184 }
185 if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
186 /* Need to do one or more global updates. Arrange
187 for this to happen. */
188 unsigned long m2;
189 pvr2_trace(PVR2_TRACE_I2C_CORE,
190 "i2c: PEND_STALE (0x%lx)",
191 hdw->i2c_stale_mask);
192 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
193 list_for_each_entry(cp, &hdw->i2c_clients, list) {
194 m2 = hdw->i2c_stale_mask;
195 m2 &= cp->ctl_mask;
196 m2 &= ~cp->pend_mask;
197 if (m2) {
198 pvr2_trace(PVR2_TRACE_I2C_CORE,
199 "i2c: cp=%p setting 0x%lx",
200 cp,m2);
201 cp->pend_mask |= m2;
202 }
203 }
204 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
205 hdw->i2c_stale_mask = 0;
206 hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
207 }
208 if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
209 /* One or more client handlers are asking for an
210 update. Run through the list of known clients
211 and update each one. */
212 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
213 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
214 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients,
215 list) {
216 if (!cp->handler) continue;
217 if (!cp->handler->func_table->update) continue;
218 pvr2_trace(PVR2_TRACE_I2C_CORE,
219 "i2c: cp=%p update",cp);
220 mutex_unlock(&hdw->i2c_list_lock);
221 cp->handler->func_table->update(
222 cp->handler->func_data);
223 mutex_lock(&hdw->i2c_list_lock);
224 /* If client's update function set some
225 additional pending bits, account for that
226 here. */
227 if (cp->pend_mask & ~hdw->i2c_pend_mask) {
228 hdw->i2c_pend_mask |= cp->pend_mask;
229 hdw->i2c_pend_types |=
230 PVR2_I2C_PEND_REFRESH;
231 }
232 }
233 }
234 if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
235 const struct pvr2_i2c_op *opf;
236 unsigned long pm;
237 /* Some actual updates are pending. Walk through
238 each update type and perform it. */
239 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
240 " (0x%lx)",hdw->i2c_pend_mask);
241 hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
242 pm = hdw->i2c_pend_mask;
243 hdw->i2c_pend_mask = 0;
244 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
245 if (!(pm & msk)) continue;
246 pm &= ~msk;
247 list_for_each_entry(cp, &hdw->i2c_clients,
248 list) {
249 if (cp->pend_mask & msk) {
250 cp->pend_mask &= ~msk;
251 cp->recv_enable = !0;
252 } else {
253 cp->recv_enable = 0;
254 }
255 }
256 opf = pvr2_i2c_get_op(idx);
257 if (!opf) continue;
258 mutex_unlock(&hdw->i2c_list_lock);
259 opf->update(hdw);
260 mutex_lock(&hdw->i2c_list_lock);
261 }
262 }
263 pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
264 } while (0); mutex_unlock(&hdw->i2c_list_lock);
265 }
266
267 int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
268 {
269 unsigned long msk,sm,pm;
270 unsigned int idx;
271 const struct pvr2_i2c_op *opf;
272 struct pvr2_i2c_client *cp;
273 unsigned int pt = 0;
274
275 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
276
277 pm = hdw->i2c_active_mask;
278 sm = 0;
279 for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
280 if (!(msk & pm)) continue;
281 pm &= ~msk;
282 opf = pvr2_i2c_get_op(idx);
283 if (!(opf && opf->check)) continue;
284 if (opf->check(hdw)) {
285 sm |= msk;
286 }
287 }
288 if (sm) pt |= PVR2_I2C_PEND_STALE;
289
290 list_for_each_entry(cp, &hdw->i2c_clients, list)
291 if (handler_check(cp))
292 pt |= PVR2_I2C_PEND_CLIENT;
293
294 if (pt) {
295 mutex_lock(&hdw->i2c_list_lock); do {
296 hdw->i2c_pend_types |= pt;
297 hdw->i2c_stale_mask |= sm;
298 hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
299 } while (0); mutex_unlock(&hdw->i2c_list_lock);
300 }
301
302 pvr2_trace(PVR2_TRACE_I2C_CORE,
303 "i2c: types=0x%x stale=0x%lx pend=0x%lx",
304 hdw->i2c_pend_types,
305 hdw->i2c_stale_mask,
306 hdw->i2c_pend_mask);
307 pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
308
309 return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
310 }
311
312 static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
313 unsigned int detail,
314 char *buf,unsigned int maxlen)
315 {
316 unsigned int ccnt,bcnt;
317 int spcfl = 0;
318 const struct pvr2_i2c_op *opf;
319
320 ccnt = 0;
321 if (detail & PVR2_I2C_DETAIL_DEBUG) {
322 bcnt = scnprintf(buf,maxlen,
323 "ctxt=%p ctl_mask=0x%lx",
324 cp,cp->ctl_mask);
325 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
326 spcfl = !0;
327 }
328 bcnt = scnprintf(buf,maxlen,
329 "%s%s @ 0x%x",
330 (spcfl ? " " : ""),
331 cp->client->name,
332 cp->client->addr);
333 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
334 if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
335 cp->handler && cp->handler->func_table->describe) {
336 bcnt = scnprintf(buf,maxlen," (");
337 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
338 bcnt = cp->handler->func_table->describe(
339 cp->handler->func_data,buf,maxlen);
340 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
341 bcnt = scnprintf(buf,maxlen,")");
342 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
343 }
344 if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
345 unsigned int idx;
346 unsigned long msk,sm;
347
348 bcnt = scnprintf(buf,maxlen," [");
349 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
350 sm = 0;
351 spcfl = 0;
352 for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
353 if (!(cp->ctl_mask & msk)) continue;
354 opf = pvr2_i2c_get_op(idx);
355 if (opf) {
356 bcnt = scnprintf(buf,maxlen,"%s%s",
357 spcfl ? " " : "",
358 opf->name);
359 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
360 spcfl = !0;
361 } else {
362 sm |= msk;
363 }
364 }
365 if (sm) {
366 bcnt = scnprintf(buf,maxlen,"%s%lx",
367 idx != 0 ? " " : "",sm);
368 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
369 }
370 bcnt = scnprintf(buf,maxlen,"]");
371 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
372 }
373 return ccnt;
374 }
375
376 unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
377 char *buf,unsigned int maxlen)
378 {
379 unsigned int ccnt,bcnt;
380 struct pvr2_i2c_client *cp;
381 ccnt = 0;
382 mutex_lock(&hdw->i2c_list_lock); do {
383 list_for_each_entry(cp, &hdw->i2c_clients, list) {
384 bcnt = pvr2_i2c_client_describe(
385 cp,
386 (PVR2_I2C_DETAIL_HANDLER|
387 PVR2_I2C_DETAIL_CTLMASK),
388 buf,maxlen);
389 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
390 bcnt = scnprintf(buf,maxlen,"\n");
391 ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
392 }
393 } while (0); mutex_unlock(&hdw->i2c_list_lock);
394 return ccnt;
395 }
396
397 void pvr2_i2c_track_attach_inform(struct i2c_client *client)
398 {
399 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
400 struct pvr2_i2c_client *cp;
401 int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
402 cp = kzalloc(sizeof(*cp),GFP_KERNEL);
403 trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
404 client->name,
405 client->addr,cp);
406 if (!cp) {
407 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
408 "Unable to allocate tracking memory for incoming"
409 " i2c module; ignoring module. This is likely"
410 " going to be a problem.");
411 return;
412 }
413 cp->hdw = hdw;
414 INIT_LIST_HEAD(&cp->list);
415 cp->client = client;
416 mutex_lock(&hdw->i2c_list_lock); do {
417 hdw->cropcap_stale = !0;
418 list_add_tail(&cp->list,&hdw->i2c_clients);
419 hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
420 } while (0); mutex_unlock(&hdw->i2c_list_lock);
421 if (fl) queue_work(hdw->workqueue,&hdw->worki2csync);
422 }
423
424 static void pvr2_i2c_client_disconnect(struct pvr2_i2c_client *cp)
425 {
426 if (cp->handler && cp->handler->func_table->detach) {
427 cp->handler->func_table->detach(cp->handler->func_data);
428 }
429 list_del(&cp->list);
430 kfree(cp);
431 }
432
433 void pvr2_i2c_track_detach_inform(struct i2c_client *client)
434 {
435 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
436 struct pvr2_i2c_client *cp, *ncp;
437 unsigned long amask = 0;
438 int foundfl = 0;
439 mutex_lock(&hdw->i2c_list_lock);
440 hdw->cropcap_stale = !0;
441 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
442 if (cp->client == client) {
443 trace_i2c("pvr2_i2c_detach"
444 " [client=%s @ 0x%x ctxt=%p]",
445 client->name,
446 client->addr, cp);
447 pvr2_i2c_client_disconnect(cp);
448 foundfl = !0;
449 continue;
450 }
451 amask |= cp->ctl_mask;
452 }
453 hdw->i2c_active_mask = amask;
454 mutex_unlock(&hdw->i2c_list_lock);
455 if (!foundfl) {
456 trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
457 client->name, client->addr);
458 }
459 }
460
461 /* This function is used to remove an i2c client from our tracking
462 structure if the client happens to be the specified v4l2 sub-device.
463 The idea here is to ensure that sub-devices are not also tracked with
464 the old tracking mechanism - it's one or the other not both. This is
465 only for debugging. In a "real" environment, only one of these two
466 mechanisms should even be compiled in. But by enabling both we can
467 incrementally test control of each sub-device. */
468 void pvr2_i2c_untrack_subdev(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
469 {
470 struct i2c_client *client;
471 struct pvr2_i2c_client *cp, *ncp;
472 unsigned long amask = 0;
473 mutex_lock(&hdw->i2c_list_lock);
474 list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) {
475 client = cp->client;
476 if (i2c_get_clientdata(client) == sd) {
477 trace_i2c("pvr2_i2c_detach (subdev active)"
478 " [client=%s @ 0x%x ctxt=%p]",
479 client->name, client->addr, cp);
480 pvr2_i2c_client_disconnect(cp);
481 continue;
482 }
483 amask |= cp->ctl_mask;
484 }
485 hdw->i2c_active_mask = amask;
486 mutex_unlock(&hdw->i2c_list_lock);
487 }
488
489 void pvr2_i2c_track_init(struct pvr2_hdw *hdw)
490 {
491 hdw->i2c_pend_mask = 0;
492 hdw->i2c_stale_mask = 0;
493 hdw->i2c_active_mask = 0;
494 INIT_LIST_HEAD(&hdw->i2c_clients);
495 mutex_init(&hdw->i2c_list_lock);
496 }
497
498 void pvr2_i2c_track_done(struct pvr2_hdw *hdw)
499 {
500 /* Empty for now */
501 }
502
503
504 /*
505 Stuff for Emacs to see, in order to encourage consistent editing style:
506 *** Local Variables: ***
507 *** mode: c ***
508 *** fill-column: 75 ***
509 *** tab-width: 8 ***
510 *** c-basic-offset: 8 ***
511 *** End: ***
512 */
This page took 0.041007 seconds and 5 git commands to generate.