4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
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
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.
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
21 #include "pvrusb2-i2c-track.h"
22 #include "pvrusb2-hdw-internal.h"
23 #include "pvrusb2-debug.h"
24 #include "pvrusb2-fx2-cmd.h"
27 #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
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
40 static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client
*cp
,
42 char *buf
,unsigned int maxlen
);
44 static int pvr2_i2c_core_singleton(struct i2c_client
*cp
,
45 unsigned int cmd
,void *arg
)
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
);
57 int pvr2_i2c_client_cmd(struct pvr2_i2c_client
*cp
,unsigned int cmd
,void *arg
)
60 if (pvrusb2_debug
& PVR2_TRACE_I2C_CMD
) {
63 cnt
= pvr2_i2c_client_describe(cp
,PVR2_I2C_DETAIL_DEBUG
,
65 pvr2_trace(PVR2_TRACE_I2C_CMD
,
66 "i2c COMMAND (code=%u 0x%x) to %.*s",
69 stat
= pvr2_i2c_core_singleton(cp
->client
,cmd
,arg
);
70 if (pvrusb2_debug
& PVR2_TRACE_I2C_CMD
) {
73 cnt
= pvr2_i2c_client_describe(cp
,PVR2_I2C_DETAIL_DEBUG
,
75 pvr2_trace(PVR2_TRACE_I2C_CMD
,
76 "i2c COMMAND to %.*s (ret=%d)",cnt
,buf
,stat
);
81 int pvr2_i2c_core_cmd(struct pvr2_hdw
*hdw
,unsigned int cmd
,void *arg
)
83 struct pvr2_i2c_client
*cp
, *ncp
;
86 if (!hdw
) return stat
;
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
);
95 mutex_unlock(&hdw
->i2c_list_lock
);
100 static int handler_check(struct pvr2_i2c_client
*cp
)
102 struct pvr2_i2c_handler
*hp
= cp
->handler
;
104 if (!hp
->func_table
->check
) return 0;
105 return hp
->func_table
->check(hp
->func_data
) != 0;
111 void pvr2_i2c_core_status_poll(struct pvr2_hdw
*hdw
)
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;
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"
127 vtp
->signal
,vtp
->rxsubchans
,vtp
->capability
,
128 vtp
->rangelow
,vtp
->rangehigh
);
129 } while (0); mutex_unlock(&hdw
->i2c_list_lock
);
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
)
139 struct pvr2_i2c_client
*cp
, *ncp
;
141 if (!hdw
->i2c_linked
) return;
142 if (!(hdw
->i2c_pend_types
& PVR2_I2C_PEND_ALL
)) {
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
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
) {
160 pvr2_i2c_probe(hdw
,cp
);
161 cp
->detected_flag
= !0;
165 cnt
= pvr2_i2c_client_describe(
170 trace_i2c("Probed: %.*s",cnt
,buf
);
171 if (handler_check(cp
)) {
172 hdw
->i2c_pend_types
|=
173 PVR2_I2C_PEND_CLIENT
;
176 hdw
->i2c_pend_mask
|= msk
;
177 hdw
->i2c_pend_types
|=
178 PVR2_I2C_PEND_REFRESH
;
180 amask
|= cp
->ctl_mask
;
182 hdw
->i2c_active_mask
= amask
;
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. */
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
;
196 m2
&= ~cp
->pend_mask
;
198 pvr2_trace(PVR2_TRACE_I2C_CORE
,
199 "i2c: cp=%p setting 0x%lx",
204 hdw
->i2c_pend_mask
|= hdw
->i2c_stale_mask
;
205 hdw
->i2c_stale_mask
= 0;
206 hdw
->i2c_pend_types
|= PVR2_I2C_PEND_REFRESH
;
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
,
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
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
;
234 if (hdw
->i2c_pend_types
& PVR2_I2C_PEND_REFRESH
) {
235 const struct pvr2_i2c_op
*opf
;
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;
247 list_for_each_entry(cp
, &hdw
->i2c_clients
,
249 if (cp
->pend_mask
& msk
) {
250 cp
->pend_mask
&= ~msk
;
251 cp
->recv_enable
= !0;
256 opf
= pvr2_i2c_get_op(idx
);
258 mutex_unlock(&hdw
->i2c_list_lock
);
260 mutex_lock(&hdw
->i2c_list_lock
);
263 pvr2_trace(PVR2_TRACE_I2C_CORE
,"i2c: core_sync END");
264 } while (0); mutex_unlock(&hdw
->i2c_list_lock
);
267 int pvr2_i2c_core_check_stale(struct pvr2_hdw
*hdw
)
269 unsigned long msk
,sm
,pm
;
271 const struct pvr2_i2c_op
*opf
;
272 struct pvr2_i2c_client
*cp
;
275 pvr2_trace(PVR2_TRACE_I2C_CORE
,"pvr2_i2c_core_check_stale BEGIN");
277 pm
= hdw
->i2c_active_mask
;
279 for (idx
= 0, msk
= 1; pm
; idx
++, msk
<<= 1) {
280 if (!(msk
& pm
)) continue;
282 opf
= pvr2_i2c_get_op(idx
);
283 if (!(opf
&& opf
->check
)) continue;
284 if (opf
->check(hdw
)) {
288 if (sm
) pt
|= PVR2_I2C_PEND_STALE
;
290 list_for_each_entry(cp
, &hdw
->i2c_clients
, list
)
291 if (handler_check(cp
))
292 pt
|= PVR2_I2C_PEND_CLIENT
;
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
);
302 pvr2_trace(PVR2_TRACE_I2C_CORE
,
303 "i2c: types=0x%x stale=0x%lx pend=0x%lx",
307 pvr2_trace(PVR2_TRACE_I2C_CORE
,"pvr2_i2c_core_check_stale END");
309 return (hdw
->i2c_pend_types
& PVR2_I2C_PEND_ALL
) != 0;
312 static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client
*cp
,
314 char *buf
,unsigned int maxlen
)
316 unsigned int ccnt
,bcnt
;
318 const struct pvr2_i2c_op
*opf
;
321 if (detail
& PVR2_I2C_DETAIL_DEBUG
) {
322 bcnt
= scnprintf(buf
,maxlen
,
323 "ctxt=%p ctl_mask=0x%lx",
325 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
328 bcnt
= scnprintf(buf
,maxlen
,
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
;
344 if ((detail
& PVR2_I2C_DETAIL_CTLMASK
) && cp
->ctl_mask
) {
346 unsigned long msk
,sm
;
348 bcnt
= scnprintf(buf
,maxlen
," [");
349 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
352 for (idx
= 0, msk
= 1; msk
; idx
++, msk
<<= 1) {
353 if (!(cp
->ctl_mask
& msk
)) continue;
354 opf
= pvr2_i2c_get_op(idx
);
356 bcnt
= scnprintf(buf
,maxlen
,"%s%s",
359 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
366 bcnt
= scnprintf(buf
,maxlen
,"%s%lx",
367 idx
!= 0 ? " " : "",sm
);
368 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
370 bcnt
= scnprintf(buf
,maxlen
,"]");
371 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
376 unsigned int pvr2_i2c_report(struct pvr2_hdw
*hdw
,
377 char *buf
,unsigned int maxlen
)
379 unsigned int ccnt
,bcnt
;
380 struct pvr2_i2c_client
*cp
;
382 mutex_lock(&hdw
->i2c_list_lock
); do {
383 list_for_each_entry(cp
, &hdw
->i2c_clients
, list
) {
384 bcnt
= pvr2_i2c_client_describe(
386 (PVR2_I2C_DETAIL_HANDLER
|
387 PVR2_I2C_DETAIL_CTLMASK
),
389 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
390 bcnt
= scnprintf(buf
,maxlen
,"\n");
391 ccnt
+= bcnt
; buf
+= bcnt
; maxlen
-= bcnt
;
393 } while (0); mutex_unlock(&hdw
->i2c_list_lock
);
397 void pvr2_i2c_track_attach_inform(struct i2c_client
*client
)
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]",
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.");
414 INIT_LIST_HEAD(&cp
->list
);
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
);
424 static void pvr2_i2c_client_disconnect(struct pvr2_i2c_client
*cp
)
426 if (cp
->handler
&& cp
->handler
->func_table
->detach
) {
427 cp
->handler
->func_table
->detach(cp
->handler
->func_data
);
433 void pvr2_i2c_track_detach_inform(struct i2c_client
*client
)
435 struct pvr2_hdw
*hdw
= (struct pvr2_hdw
*)(client
->adapter
->algo_data
);
436 struct pvr2_i2c_client
*cp
, *ncp
;
437 unsigned long amask
= 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]",
447 pvr2_i2c_client_disconnect(cp
);
451 amask
|= cp
->ctl_mask
;
453 hdw
->i2c_active_mask
= amask
;
454 mutex_unlock(&hdw
->i2c_list_lock
);
456 trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
457 client
->name
, client
->addr
);
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
)
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
) {
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
);
483 amask
|= cp
->ctl_mask
;
485 hdw
->i2c_active_mask
= amask
;
486 mutex_unlock(&hdw
->i2c_list_lock
);
489 void pvr2_i2c_track_init(struct pvr2_hdw
*hdw
)
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
);
498 void pvr2_i2c_track_done(struct pvr2_hdw
*hdw
)
505 Stuff for Emacs to see, in order to encourage consistent editing style:
506 *** Local Variables: ***
508 *** fill-column: 75 ***
510 *** c-basic-offset: 8 ***
This page took 0.041007 seconds and 5 git commands to generate.