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