]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/dvb/firewire/firedtv-avc.c
Merge branch 'thermal' into release
[linux-2.6-omap-h63xx.git] / drivers / media / dvb / firewire / firedtv-avc.c
1 /*
2  * FireDTV driver (formerly known as FireSAT)
3  *
4  * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5  * Copyright (C) 2008 Ben Backx <ben@bbackx.com>
6  * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
7  *
8  *      This program is free software; you can redistribute it and/or
9  *      modify it under the terms of the GNU General Public License as
10  *      published by the Free Software Foundation; either version 2 of
11  *      the License, or (at your option) any later version.
12  */
13
14 #include <linux/bug.h>
15 #include <linux/crc32.h>
16 #include <linux/delay.h>
17 #include <linux/device.h>
18 #include <linux/jiffies.h>
19 #include <linux/kernel.h>
20 #include <linux/moduleparam.h>
21 #include <linux/mutex.h>
22 #include <linux/string.h>
23 #include <linux/stringify.h>
24 #include <linux/wait.h>
25 #include <linux/workqueue.h>
26
27 #include "firedtv.h"
28
29 #define FCP_COMMAND_REGISTER            0xfffff0000b00ULL
30
31 #define AVC_CTYPE_CONTROL               0x0
32 #define AVC_CTYPE_STATUS                0x1
33 #define AVC_CTYPE_NOTIFY                0x3
34
35 #define AVC_RESPONSE_ACCEPTED           0x9
36 #define AVC_RESPONSE_STABLE             0xc
37 #define AVC_RESPONSE_CHANGED            0xd
38 #define AVC_RESPONSE_INTERIM            0xf
39
40 #define AVC_SUBUNIT_TYPE_TUNER          (0x05 << 3)
41 #define AVC_SUBUNIT_TYPE_UNIT           (0x1f << 3)
42
43 #define AVC_OPCODE_VENDOR               0x00
44 #define AVC_OPCODE_READ_DESCRIPTOR      0x09
45 #define AVC_OPCODE_DSIT                 0xc8
46 #define AVC_OPCODE_DSD                  0xcb
47
48 #define DESCRIPTOR_TUNER_STATUS         0x80
49 #define DESCRIPTOR_SUBUNIT_IDENTIFIER   0x00
50
51 #define SFE_VENDOR_DE_COMPANYID_0       0x00 /* OUI of Digital Everywhere */
52 #define SFE_VENDOR_DE_COMPANYID_1       0x12
53 #define SFE_VENDOR_DE_COMPANYID_2       0x87
54
55 #define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a
56 #define SFE_VENDOR_OPCODE_LNB_CONTROL           0x52
57 #define SFE_VENDOR_OPCODE_TUNE_QPSK             0x58 /* for DVB-S */
58
59 #define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION  0x00
60 #define SFE_VENDOR_OPCODE_HOST2CA               0x56
61 #define SFE_VENDOR_OPCODE_CA2HOST               0x57
62 #define SFE_VENDOR_OPCODE_CISTATUS              0x59
63 #define SFE_VENDOR_OPCODE_TUNE_QPSK2            0x60 /* for DVB-S2 */
64
65 #define SFE_VENDOR_TAG_CA_RESET                 0x00
66 #define SFE_VENDOR_TAG_CA_APPLICATION_INFO      0x01
67 #define SFE_VENDOR_TAG_CA_PMT                   0x02
68 #define SFE_VENDOR_TAG_CA_DATE_TIME             0x04
69 #define SFE_VENDOR_TAG_CA_MMI                   0x05
70 #define SFE_VENDOR_TAG_CA_ENTER_MENU            0x07
71
72 #define EN50221_LIST_MANAGEMENT_ONLY    0x03
73 #define EN50221_TAG_APP_INFO            0x9f8021
74 #define EN50221_TAG_CA_INFO             0x9f8031
75
76 struct avc_command_frame {
77         int length;
78         u8 ctype;
79         u8 subunit;
80         u8 opcode;
81         u8 operand[509];
82 };
83
84 struct avc_response_frame {
85         int length;
86         u8 response;
87         u8 subunit;
88         u8 opcode;
89         u8 operand[509];
90 };
91
92 #define AVC_DEBUG_FCP_SUBACTIONS        1
93 #define AVC_DEBUG_FCP_PAYLOADS          2
94
95 static int avc_debug;
96 module_param_named(debug, avc_debug, int, 0644);
97 MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
98         ", FCP subactions = "   __stringify(AVC_DEBUG_FCP_SUBACTIONS)
99         ", FCP payloads = "     __stringify(AVC_DEBUG_FCP_PAYLOADS)
100         ", or all = -1)");
101
102 static const char *debug_fcp_ctype(unsigned int ctype)
103 {
104         static const char *ctypes[] = {
105                 [0x0] = "CONTROL",              [0x1] = "STATUS",
106                 [0x2] = "SPECIFIC INQUIRY",     [0x3] = "NOTIFY",
107                 [0x4] = "GENERAL INQUIRY",      [0x8] = "NOT IMPLEMENTED",
108                 [0x9] = "ACCEPTED",             [0xa] = "REJECTED",
109                 [0xb] = "IN TRANSITION",        [0xc] = "IMPLEMENTED/STABLE",
110                 [0xd] = "CHANGED",              [0xf] = "INTERIM",
111         };
112         const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
113
114         return ret ? ret : "?";
115 }
116
117 static const char *debug_fcp_opcode(unsigned int opcode,
118                                     const u8 *data, size_t length)
119 {
120         switch (opcode) {
121         case AVC_OPCODE_VENDOR:                 break;
122         case AVC_OPCODE_READ_DESCRIPTOR:        return "ReadDescriptor";
123         case AVC_OPCODE_DSIT:                   return "DirectSelectInfo.Type";
124         case AVC_OPCODE_DSD:                    return "DirectSelectData";
125         default:                                return "?";
126         }
127
128         if (length < 7 ||
129             data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
130             data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
131             data[5] != SFE_VENDOR_DE_COMPANYID_2)
132                 return "Vendor";
133
134         switch (data[6]) {
135         case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC";
136         case SFE_VENDOR_OPCODE_LNB_CONTROL:             return "LNBControl";
137         case SFE_VENDOR_OPCODE_TUNE_QPSK:               return "TuneQPSK";
138         case SFE_VENDOR_OPCODE_HOST2CA:                 return "Host2CA";
139         case SFE_VENDOR_OPCODE_CA2HOST:                 return "CA2Host";
140         }
141         return "Vendor";
142 }
143
144 static void debug_fcp(const u8 *data, size_t length)
145 {
146         unsigned int subunit_type, subunit_id, op;
147         const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
148
149         if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) {
150                 subunit_type = data[1] >> 3;
151                 subunit_id = data[1] & 7;
152                 op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
153                 printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
154                        prefix, subunit_type, subunit_id, length,
155                        debug_fcp_ctype(data[0]),
156                        debug_fcp_opcode(op, data, length));
157         }
158
159         if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
160                 print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1,
161                                data, length, false);
162 }
163
164 static int __avc_write(struct firedtv *fdtv,
165                 const struct avc_command_frame *c, struct avc_response_frame *r)
166 {
167         int err, retry;
168
169         if (r)
170                 fdtv->avc_reply_received = false;
171
172         for (retry = 0; retry < 6; retry++) {
173                 if (unlikely(avc_debug))
174                         debug_fcp(&c->ctype, c->length);
175
176                 err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
177                                            (void *)&c->ctype, c->length);
178                 if (err) {
179                         fdtv->avc_reply_received = true;
180                         dev_err(fdtv->device, "FCP command write failed\n");
181                         return err;
182                 }
183
184                 if (!r)
185                         return 0;
186
187                 /*
188                  * AV/C specs say that answers should be sent within 150 ms.
189                  * Time out after 200 ms.
190                  */
191                 if (wait_event_timeout(fdtv->avc_wait,
192                                        fdtv->avc_reply_received,
193                                        msecs_to_jiffies(200)) != 0) {
194                         r->length = fdtv->response_length;
195                         memcpy(&r->response, fdtv->response, r->length);
196
197                         return 0;
198                 }
199         }
200         dev_err(fdtv->device, "FCP response timed out\n");
201         return -ETIMEDOUT;
202 }
203
204 static int avc_write(struct firedtv *fdtv,
205                 const struct avc_command_frame *c, struct avc_response_frame *r)
206 {
207         int ret;
208
209         if (mutex_lock_interruptible(&fdtv->avc_mutex))
210                 return -EINTR;
211
212         ret = __avc_write(fdtv, c, r);
213
214         mutex_unlock(&fdtv->avc_mutex);
215         return ret;
216 }
217
218 int avc_recv(struct firedtv *fdtv, void *data, size_t length)
219 {
220         struct avc_response_frame *r =
221                         data - offsetof(struct avc_response_frame, response);
222
223         if (unlikely(avc_debug))
224                 debug_fcp(data, length);
225
226         if (length >= 8 &&
227             r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
228             r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
229             r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
230             r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
231                 if (r->response == AVC_RESPONSE_CHANGED) {
232                         fdtv_handle_rc(fdtv,
233                             r->operand[4] << 8 | r->operand[5]);
234                         schedule_work(&fdtv->remote_ctrl_work);
235                 } else if (r->response != AVC_RESPONSE_INTERIM) {
236                         dev_info(fdtv->device,
237                                  "remote control result = %d\n", r->response);
238                 }
239                 return 0;
240         }
241
242         if (fdtv->avc_reply_received) {
243                 dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
244                 return -EIO;
245         }
246
247         memcpy(fdtv->response, data, length);
248         fdtv->response_length = length;
249
250         fdtv->avc_reply_received = true;
251         wake_up(&fdtv->avc_wait);
252
253         return 0;
254 }
255
256 /*
257  * tuning command for setting the relative LNB frequency
258  * (not supported by the AVC standard)
259  */
260 static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
261                                struct dvb_frontend_parameters *params,
262                                struct avc_command_frame *c)
263 {
264         c->opcode = AVC_OPCODE_VENDOR;
265
266         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
267         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
268         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
269         c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
270
271         c->operand[4] = (params->frequency >> 24) & 0xff;
272         c->operand[5] = (params->frequency >> 16) & 0xff;
273         c->operand[6] = (params->frequency >> 8) & 0xff;
274         c->operand[7] = params->frequency & 0xff;
275
276         c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
277         c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
278
279         switch (params->u.qpsk.fec_inner) {
280         case FEC_1_2:   c->operand[10] = 0x1; break;
281         case FEC_2_3:   c->operand[10] = 0x2; break;
282         case FEC_3_4:   c->operand[10] = 0x3; break;
283         case FEC_5_6:   c->operand[10] = 0x4; break;
284         case FEC_7_8:   c->operand[10] = 0x5; break;
285         case FEC_4_5:
286         case FEC_8_9:
287         case FEC_AUTO:
288         default:        c->operand[10] = 0x0;
289         }
290
291         if (fdtv->voltage == 0xff)
292                 c->operand[11] = 0xff;
293         else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
294                 c->operand[11] = 0;
295         else
296                 c->operand[11] = 1;
297
298         if (fdtv->tone == 0xff)
299                 c->operand[12] = 0xff;
300         else if (fdtv->tone == SEC_TONE_ON) /* band */
301                 c->operand[12] = 1;
302         else
303                 c->operand[12] = 0;
304
305         if (fdtv->type == FIREDTV_DVB_S2) {
306                 c->operand[13] = 0x1;
307                 c->operand[14] = 0xff;
308                 c->operand[15] = 0xff;
309                 c->length = 20;
310         } else {
311                 c->length = 16;
312         }
313 }
314
315 static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
316                                 struct avc_command_frame *c)
317 {
318         c->opcode = AVC_OPCODE_DSD;
319
320         c->operand[0] = 0;    /* source plug */
321         c->operand[1] = 0xd2; /* subfunction replace */
322         c->operand[2] = 0x20; /* system id = DVB */
323         c->operand[3] = 0x00; /* antenna number */
324         c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
325
326         /* multiplex_valid_flags, high byte */
327         c->operand[5] =   0 << 7 /* reserved */
328                         | 0 << 6 /* Polarisation */
329                         | 0 << 5 /* Orbital_Pos */
330                         | 1 << 4 /* Frequency */
331                         | 1 << 3 /* Symbol_Rate */
332                         | 0 << 2 /* FEC_outer */
333                         | (params->u.qam.fec_inner  != FEC_AUTO ? 1 << 1 : 0)
334                         | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
335
336         /* multiplex_valid_flags, low byte */
337         c->operand[6] =   0 << 7 /* NetworkID */
338                         | 0 << 0 /* reserved */ ;
339
340         c->operand[7]  = 0x00;
341         c->operand[8]  = 0x00;
342         c->operand[9]  = 0x00;
343         c->operand[10] = 0x00;
344
345         c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
346         c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
347         c->operand[13] = (params->frequency / 4000) & 0xff;
348         c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
349         c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
350         c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
351         c->operand[17] = 0x00;
352
353         switch (params->u.qpsk.fec_inner) {
354         case FEC_1_2:   c->operand[18] = 0x1; break;
355         case FEC_2_3:   c->operand[18] = 0x2; break;
356         case FEC_3_4:   c->operand[18] = 0x3; break;
357         case FEC_5_6:   c->operand[18] = 0x4; break;
358         case FEC_7_8:   c->operand[18] = 0x5; break;
359         case FEC_8_9:   c->operand[18] = 0x6; break;
360         case FEC_4_5:   c->operand[18] = 0x8; break;
361         case FEC_AUTO:
362         default:        c->operand[18] = 0x0;
363         }
364
365         switch (params->u.qam.modulation) {
366         case QAM_16:    c->operand[19] = 0x08; break;
367         case QAM_32:    c->operand[19] = 0x10; break;
368         case QAM_64:    c->operand[19] = 0x18; break;
369         case QAM_128:   c->operand[19] = 0x20; break;
370         case QAM_256:   c->operand[19] = 0x28; break;
371         case QAM_AUTO:
372         default:        c->operand[19] = 0x00;
373         }
374
375         c->operand[20] = 0x00;
376         c->operand[21] = 0x00;
377         /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
378         c->operand[22] = 0x00;
379
380         c->length = 28;
381 }
382
383 static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
384                                 struct avc_command_frame *c)
385 {
386         struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
387
388         c->opcode = AVC_OPCODE_DSD;
389
390         c->operand[0] = 0;    /* source plug */
391         c->operand[1] = 0xd2; /* subfunction replace */
392         c->operand[2] = 0x20; /* system id = DVB */
393         c->operand[3] = 0x00; /* antenna number */
394         c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
395
396         /* multiplex_valid_flags, high byte */
397         c->operand[5] =
398               0 << 7 /* reserved */
399             | 1 << 6 /* CenterFrequency */
400             | (ofdm->bandwidth      != BANDWIDTH_AUTO        ? 1 << 5 : 0)
401             | (ofdm->constellation  != QAM_AUTO              ? 1 << 4 : 0)
402             | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
403             | (ofdm->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
404             | (ofdm->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
405             | (ofdm->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
406
407         /* multiplex_valid_flags, low byte */
408         c->operand[6] =
409               0 << 7 /* NetworkID */
410             | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
411             | 0 << 5 /* OtherFrequencyFlag */
412             | 0 << 0 /* reserved */ ;
413
414         c->operand[7]  = 0x0;
415         c->operand[8]  = (params->frequency / 10) >> 24;
416         c->operand[9]  = ((params->frequency / 10) >> 16) & 0xff;
417         c->operand[10] = ((params->frequency / 10) >>  8) & 0xff;
418         c->operand[11] = (params->frequency / 10) & 0xff;
419
420         switch (ofdm->bandwidth) {
421         case BANDWIDTH_7_MHZ:   c->operand[12] = 0x20; break;
422         case BANDWIDTH_8_MHZ:
423         case BANDWIDTH_6_MHZ:   /* not defined by AVC spec */
424         case BANDWIDTH_AUTO:
425         default:                c->operand[12] = 0x00;
426         }
427
428         switch (ofdm->constellation) {
429         case QAM_16:    c->operand[13] = 1 << 6; break;
430         case QAM_64:    c->operand[13] = 2 << 6; break;
431         case QPSK:
432         default:        c->operand[13] = 0x00;
433         }
434
435         switch (ofdm->hierarchy_information) {
436         case HIERARCHY_1:       c->operand[13] |= 1 << 3; break;
437         case HIERARCHY_2:       c->operand[13] |= 2 << 3; break;
438         case HIERARCHY_4:       c->operand[13] |= 3 << 3; break;
439         case HIERARCHY_AUTO:
440         case HIERARCHY_NONE:
441         default:                break;
442         }
443
444         switch (ofdm->code_rate_HP) {
445         case FEC_2_3:   c->operand[13] |= 1; break;
446         case FEC_3_4:   c->operand[13] |= 2; break;
447         case FEC_5_6:   c->operand[13] |= 3; break;
448         case FEC_7_8:   c->operand[13] |= 4; break;
449         case FEC_1_2:
450         default:        break;
451         }
452
453         switch (ofdm->code_rate_LP) {
454         case FEC_2_3:   c->operand[14] = 1 << 5; break;
455         case FEC_3_4:   c->operand[14] = 2 << 5; break;
456         case FEC_5_6:   c->operand[14] = 3 << 5; break;
457         case FEC_7_8:   c->operand[14] = 4 << 5; break;
458         case FEC_1_2:
459         default:        c->operand[14] = 0x00; break;
460         }
461
462         switch (ofdm->guard_interval) {
463         case GUARD_INTERVAL_1_16:       c->operand[14] |= 1 << 3; break;
464         case GUARD_INTERVAL_1_8:        c->operand[14] |= 2 << 3; break;
465         case GUARD_INTERVAL_1_4:        c->operand[14] |= 3 << 3; break;
466         case GUARD_INTERVAL_1_32:
467         case GUARD_INTERVAL_AUTO:
468         default:                        break;
469         }
470
471         switch (ofdm->transmission_mode) {
472         case TRANSMISSION_MODE_8K:      c->operand[14] |= 1 << 1; break;
473         case TRANSMISSION_MODE_2K:
474         case TRANSMISSION_MODE_AUTO:
475         default:                        break;
476         }
477
478         c->operand[15] = 0x00; /* network_ID[0] */
479         c->operand[16] = 0x00; /* network_ID[1] */
480         /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
481         c->operand[17] = 0x00;
482
483         c->length = 24;
484 }
485
486 int avc_tuner_dsd(struct firedtv *fdtv,
487                   struct dvb_frontend_parameters *params)
488 {
489         char buffer[sizeof(struct avc_command_frame)];
490         struct avc_command_frame *c = (void *)buffer;
491         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
492
493         memset(c, 0, sizeof(*c));
494
495         c->ctype   = AVC_CTYPE_CONTROL;
496         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
497
498         switch (fdtv->type) {
499         case FIREDTV_DVB_S:
500         case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
501         case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break;
502         case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break;
503         default:
504                 BUG();
505         }
506
507         if (avc_write(fdtv, c, r) < 0)
508                 return -EIO;
509
510         msleep(500);
511 #if 0
512         /* FIXME: */
513         /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
514         if (status)
515                 *status = r->operand[2];
516 #endif
517         return 0;
518 }
519
520 int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
521 {
522         char buffer[sizeof(struct avc_command_frame)];
523         struct avc_command_frame *c = (void *)buffer;
524         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
525         int pos, k;
526
527         if (pidc > 16 && pidc != 0xff)
528                 return -EINVAL;
529
530         memset(c, 0, sizeof(*c));
531
532         c->ctype   = AVC_CTYPE_CONTROL;
533         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
534         c->opcode  = AVC_OPCODE_DSD;
535
536         c->operand[0] = 0;      /* source plug */
537         c->operand[1] = 0xd2;   /* subfunction replace */
538         c->operand[2] = 0x20;   /* system id = DVB */
539         c->operand[3] = 0x00;   /* antenna number */
540         c->operand[4] = 0x00;   /* system_specific_multiplex selection_length */
541         c->operand[5] = pidc;   /* Nr_of_dsd_sel_specs */
542
543         pos = 6;
544         if (pidc != 0xff)
545                 for (k = 0; k < pidc; k++) {
546                         c->operand[pos++] = 0x13; /* flowfunction relay */
547                         c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
548                         c->operand[pos++] = (pid[k] >> 8) & 0x1f;
549                         c->operand[pos++] = pid[k] & 0xff;
550                         c->operand[pos++] = 0x00; /* tableID */
551                         c->operand[pos++] = 0x00; /* filter_length */
552                 }
553
554         c->length = ALIGN(3 + pos, 4);
555
556         if (avc_write(fdtv, c, r) < 0)
557                 return -EIO;
558
559         msleep(50);
560         return 0;
561 }
562
563 int avc_tuner_get_ts(struct firedtv *fdtv)
564 {
565         char buffer[sizeof(struct avc_command_frame)];
566         struct avc_command_frame *c = (void *)buffer;
567         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
568         int sl;
569
570         memset(c, 0, sizeof(*c));
571
572         c->ctype   = AVC_CTYPE_CONTROL;
573         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
574         c->opcode  = AVC_OPCODE_DSIT;
575
576         sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
577
578         c->operand[0] = 0;      /* source plug */
579         c->operand[1] = 0xd2;   /* subfunction replace */
580         c->operand[2] = 0xff;   /* status */
581         c->operand[3] = 0x20;   /* system id = DVB */
582         c->operand[4] = 0x00;   /* antenna number */
583         c->operand[5] = 0x0;    /* system_specific_search_flags */
584         c->operand[6] = sl;     /* system_specific_multiplex selection_length */
585         c->operand[7] = 0x00;   /* valid_flags [0] */
586         c->operand[8] = 0x00;   /* valid_flags [1] */
587         c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
588
589         c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
590
591         if (avc_write(fdtv, c, r) < 0)
592                 return -EIO;
593
594         msleep(250);
595         return 0;
596 }
597
598 int avc_identify_subunit(struct firedtv *fdtv)
599 {
600         char buffer[sizeof(struct avc_command_frame)];
601         struct avc_command_frame *c = (void *)buffer;
602         struct avc_response_frame *r = (void *)buffer;
603
604         memset(c, 0, sizeof(*c));
605
606         c->ctype   = AVC_CTYPE_CONTROL;
607         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
608         c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
609
610         c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
611         c->operand[1] = 0xff;
612         c->operand[2] = 0x00;
613         c->operand[3] = 0x00; /* length highbyte */
614         c->operand[4] = 0x08; /* length lowbyte  */
615         c->operand[5] = 0x00; /* offset highbyte */
616         c->operand[6] = 0x0d; /* offset lowbyte  */
617
618         c->length = 12;
619
620         if (avc_write(fdtv, c, r) < 0)
621                 return -EIO;
622
623         if ((r->response != AVC_RESPONSE_STABLE &&
624              r->response != AVC_RESPONSE_ACCEPTED) ||
625             (r->operand[3] << 8) + r->operand[4] != 8) {
626                 dev_err(fdtv->device, "cannot read subunit identifier\n");
627                 return -EINVAL;
628         }
629         return 0;
630 }
631
632 #define SIZEOF_ANTENNA_INPUT_INFO 22
633
634 int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
635 {
636         char buffer[sizeof(struct avc_command_frame)];
637         struct avc_command_frame *c = (void *)buffer;
638         struct avc_response_frame *r = (void *)buffer;
639         int length;
640
641         memset(c, 0, sizeof(*c));
642
643         c->ctype   = AVC_CTYPE_CONTROL;
644         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
645         c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
646
647         c->operand[0] = DESCRIPTOR_TUNER_STATUS;
648         c->operand[1] = 0xff;   /* read_result_status */
649         c->operand[2] = 0x00;   /* reserved */
650         c->operand[3] = 0;      /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
651         c->operand[4] = 0;      /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
652         c->operand[5] = 0x00;
653         c->operand[6] = 0x00;
654
655         c->length = 12;
656
657         if (avc_write(fdtv, c, r) < 0)
658                 return -EIO;
659
660         if (r->response != AVC_RESPONSE_STABLE &&
661             r->response != AVC_RESPONSE_ACCEPTED) {
662                 dev_err(fdtv->device, "cannot read tuner status\n");
663                 return -EINVAL;
664         }
665
666         length = r->operand[9];
667         if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
668                 dev_err(fdtv->device, "got invalid tuner status\n");
669                 return -EINVAL;
670         }
671
672         stat->active_system             = r->operand[10];
673         stat->searching                 = r->operand[11] >> 7 & 1;
674         stat->moving                    = r->operand[11] >> 6 & 1;
675         stat->no_rf                     = r->operand[11] >> 5 & 1;
676         stat->input                     = r->operand[12] >> 7 & 1;
677         stat->selected_antenna          = r->operand[12] & 0x7f;
678         stat->ber                       = r->operand[13] << 24 |
679                                           r->operand[14] << 16 |
680                                           r->operand[15] << 8 |
681                                           r->operand[16];
682         stat->signal_strength           = r->operand[17];
683         stat->raster_frequency          = r->operand[18] >> 6 & 2;
684         stat->rf_frequency              = (r->operand[18] & 0x3f) << 16 |
685                                           r->operand[19] << 8 |
686                                           r->operand[20];
687         stat->man_dep_info_length       = r->operand[21];
688         stat->front_end_error           = r->operand[22] >> 4 & 1;
689         stat->antenna_error             = r->operand[22] >> 3 & 1;
690         stat->front_end_power_status    = r->operand[22] >> 1 & 1;
691         stat->power_supply              = r->operand[22] & 1;
692         stat->carrier_noise_ratio       = r->operand[23] << 8 |
693                                           r->operand[24];
694         stat->power_supply_voltage      = r->operand[27];
695         stat->antenna_voltage           = r->operand[28];
696         stat->firewire_bus_voltage      = r->operand[29];
697         stat->ca_mmi                    = r->operand[30] & 1;
698         stat->ca_pmt_reply              = r->operand[31] >> 7 & 1;
699         stat->ca_date_time_request      = r->operand[31] >> 6 & 1;
700         stat->ca_application_info       = r->operand[31] >> 5 & 1;
701         stat->ca_module_present_status  = r->operand[31] >> 4 & 1;
702         stat->ca_dvb_flag               = r->operand[31] >> 3 & 1;
703         stat->ca_error_flag             = r->operand[31] >> 2 & 1;
704         stat->ca_initialization_status  = r->operand[31] >> 1 & 1;
705
706         return 0;
707 }
708
709 int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
710                     char conttone, char nrdiseq,
711                     struct dvb_diseqc_master_cmd *diseqcmd)
712 {
713         char buffer[sizeof(struct avc_command_frame)];
714         struct avc_command_frame *c = (void *)buffer;
715         struct avc_response_frame *r = (void *)buffer;
716         int i, j, k;
717
718         memset(c, 0, sizeof(*c));
719
720         c->ctype   = AVC_CTYPE_CONTROL;
721         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
722         c->opcode  = AVC_OPCODE_VENDOR;
723
724         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
725         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
726         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
727         c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
728
729         c->operand[4] = voltage;
730         c->operand[5] = nrdiseq;
731
732         i = 6;
733
734         for (j = 0; j < nrdiseq; j++) {
735                 c->operand[i++] = diseqcmd[j].msg_len;
736
737                 for (k = 0; k < diseqcmd[j].msg_len; k++)
738                         c->operand[i++] = diseqcmd[j].msg[k];
739         }
740
741         c->operand[i++] = burst;
742         c->operand[i++] = conttone;
743
744         c->length = ALIGN(3 + i, 4);
745
746         if (avc_write(fdtv, c, r) < 0)
747                 return -EIO;
748
749         if (r->response != AVC_RESPONSE_ACCEPTED) {
750                 dev_err(fdtv->device, "LNB control failed\n");
751                 return -EINVAL;
752         }
753
754         return 0;
755 }
756
757 int avc_register_remote_control(struct firedtv *fdtv)
758 {
759         char buffer[sizeof(struct avc_command_frame)];
760         struct avc_command_frame *c = (void *)buffer;
761
762         memset(c, 0, sizeof(*c));
763
764         c->ctype   = AVC_CTYPE_NOTIFY;
765         c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
766         c->opcode  = AVC_OPCODE_VENDOR;
767
768         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
769         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
770         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
771         c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
772
773         c->length = 8;
774
775         return avc_write(fdtv, c, NULL);
776 }
777
778 void avc_remote_ctrl_work(struct work_struct *work)
779 {
780         struct firedtv *fdtv =
781                         container_of(work, struct firedtv, remote_ctrl_work);
782
783         /* Should it be rescheduled in failure cases? */
784         avc_register_remote_control(fdtv);
785 }
786
787 #if 0 /* FIXME: unused */
788 int avc_tuner_host2ca(struct firedtv *fdtv)
789 {
790         char buffer[sizeof(struct avc_command_frame)];
791         struct avc_command_frame *c = (void *)buffer;
792         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
793
794         memset(c, 0, sizeof(*c));
795
796         c->ctype   = AVC_CTYPE_CONTROL;
797         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
798         c->opcode  = AVC_OPCODE_VENDOR;
799
800         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
801         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
802         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
803         c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
804         c->operand[4] = 0; /* slot */
805         c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
806         c->operand[6] = 0; /* more/last */
807         c->operand[7] = 0; /* length */
808
809         c->length = 12;
810
811         if (avc_write(fdtv, c, r) < 0)
812                 return -EIO;
813
814         return 0;
815 }
816 #endif
817
818 static int get_ca_object_pos(struct avc_response_frame *r)
819 {
820         int length = 1;
821
822         /* Check length of length field */
823         if (r->operand[7] & 0x80)
824                 length = (r->operand[7] & 0x7f) + 1;
825         return length + 7;
826 }
827
828 static int get_ca_object_length(struct avc_response_frame *r)
829 {
830 #if 0 /* FIXME: unused */
831         int size = 0;
832         int i;
833
834         if (r->operand[7] & 0x80)
835                 for (i = 0; i < (r->operand[7] & 0x7f); i++) {
836                         size <<= 8;
837                         size += r->operand[8 + i];
838                 }
839 #endif
840         return r->operand[7];
841 }
842
843 int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
844 {
845         char buffer[sizeof(struct avc_command_frame)];
846         struct avc_command_frame *c = (void *)buffer;
847         struct avc_response_frame *r = (void *)buffer;
848         int pos;
849
850         memset(c, 0, sizeof(*c));
851
852         c->ctype   = AVC_CTYPE_STATUS;
853         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
854         c->opcode  = AVC_OPCODE_VENDOR;
855
856         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
857         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
858         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
859         c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
860         c->operand[4] = 0; /* slot */
861         c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
862
863         c->length = 12;
864
865         if (avc_write(fdtv, c, r) < 0)
866                 return -EIO;
867
868         /* FIXME: check response code and validate response data */
869
870         pos = get_ca_object_pos(r);
871         app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
872         app_info[1] = (EN50221_TAG_APP_INFO >>  8) & 0xff;
873         app_info[2] = (EN50221_TAG_APP_INFO >>  0) & 0xff;
874         app_info[3] = 6 + r->operand[pos + 4];
875         app_info[4] = 0x01;
876         memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
877         *len = app_info[3] + 4;
878
879         return 0;
880 }
881
882 int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
883 {
884         char buffer[sizeof(struct avc_command_frame)];
885         struct avc_command_frame *c = (void *)buffer;
886         struct avc_response_frame *r = (void *)buffer;
887         int pos;
888
889         memset(c, 0, sizeof(*c));
890
891         c->ctype   = AVC_CTYPE_STATUS;
892         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
893         c->opcode  = AVC_OPCODE_VENDOR;
894
895         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
896         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
897         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
898         c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
899         c->operand[4] = 0; /* slot */
900         c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
901
902         c->length = 12;
903
904         if (avc_write(fdtv, c, r) < 0)
905                 return -EIO;
906
907         pos = get_ca_object_pos(r);
908         app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
909         app_info[1] = (EN50221_TAG_CA_INFO >>  8) & 0xff;
910         app_info[2] = (EN50221_TAG_CA_INFO >>  0) & 0xff;
911         app_info[3] = 2;
912         app_info[4] = r->operand[pos + 0];
913         app_info[5] = r->operand[pos + 1];
914         *len = app_info[3] + 4;
915
916         return 0;
917 }
918
919 int avc_ca_reset(struct firedtv *fdtv)
920 {
921         char buffer[sizeof(struct avc_command_frame)];
922         struct avc_command_frame *c = (void *)buffer;
923         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
924
925         memset(c, 0, sizeof(*c));
926
927         c->ctype   = AVC_CTYPE_CONTROL;
928         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
929         c->opcode  = AVC_OPCODE_VENDOR;
930
931         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
932         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
933         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
934         c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
935         c->operand[4] = 0; /* slot */
936         c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
937         c->operand[6] = 0; /* more/last */
938         c->operand[7] = 1; /* length */
939         c->operand[8] = 0; /* force hardware reset */
940
941         c->length = 12;
942
943         if (avc_write(fdtv, c, r) < 0)
944                 return -EIO;
945
946         return 0;
947 }
948
949 int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
950 {
951         char buffer[sizeof(struct avc_command_frame)];
952         struct avc_command_frame *c = (void *)buffer;
953         struct avc_response_frame *r = (void *)buffer;
954         int list_management;
955         int program_info_length;
956         int pmt_cmd_id;
957         int read_pos;
958         int write_pos;
959         int es_info_length;
960         int crc32_csum;
961
962         memset(c, 0, sizeof(*c));
963
964         c->ctype   = AVC_CTYPE_CONTROL;
965         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
966         c->opcode  = AVC_OPCODE_VENDOR;
967
968         if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
969                 dev_info(fdtv->device, "forcing list_management to ONLY\n");
970                 msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
971         }
972         /* We take the cmd_id from the programme level only! */
973         list_management = msg[0];
974         program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
975         if (program_info_length > 0)
976                 program_info_length--; /* Remove pmt_cmd_id */
977         pmt_cmd_id = msg[6];
978
979         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
980         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
981         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
982         c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
983         c->operand[4] = 0; /* slot */
984         c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
985         c->operand[6] = 0; /* more/last */
986         /* c->operand[7] = XXXprogram_info_length + 17; */ /* length */
987         c->operand[8] = list_management;
988         c->operand[9] = 0x01; /* pmt_cmd=OK_descramble */
989
990         /* TS program map table */
991
992         c->operand[10] = 0x02; /* Table id=2 */
993         c->operand[11] = 0x80; /* Section syntax + length */
994         /* c->operand[12] = XXXprogram_info_length + 12; */
995         c->operand[13] = msg[1]; /* Program number */
996         c->operand[14] = msg[2];
997         c->operand[15] = 0x01; /* Version number=0 + current/next=1 */
998         c->operand[16] = 0x00; /* Section number=0 */
999         c->operand[17] = 0x00; /* Last section number=0 */
1000         c->operand[18] = 0x1f; /* PCR_PID=1FFF */
1001         c->operand[19] = 0xff;
1002         c->operand[20] = (program_info_length >> 8); /* Program info length */
1003         c->operand[21] = (program_info_length & 0xff);
1004
1005         /* CA descriptors at programme level */
1006         read_pos = 6;
1007         write_pos = 22;
1008         if (program_info_length > 0) {
1009                 pmt_cmd_id = msg[read_pos++];
1010                 if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1011                         dev_err(fdtv->device,
1012                                 "invalid pmt_cmd_id %d\n", pmt_cmd_id);
1013
1014                 memcpy(&c->operand[write_pos], &msg[read_pos],
1015                        program_info_length);
1016                 read_pos += program_info_length;
1017                 write_pos += program_info_length;
1018         }
1019         while (read_pos < length) {
1020                 c->operand[write_pos++] = msg[read_pos++];
1021                 c->operand[write_pos++] = msg[read_pos++];
1022                 c->operand[write_pos++] = msg[read_pos++];
1023                 es_info_length =
1024                         ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
1025                 read_pos += 2;
1026                 if (es_info_length > 0)
1027                         es_info_length--; /* Remove pmt_cmd_id */
1028                 c->operand[write_pos++] = es_info_length >> 8;
1029                 c->operand[write_pos++] = es_info_length & 0xff;
1030                 if (es_info_length > 0) {
1031                         pmt_cmd_id = msg[read_pos++];
1032                         if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
1033                                 dev_err(fdtv->device, "invalid pmt_cmd_id %d "
1034                                         "at stream level\n", pmt_cmd_id);
1035
1036                         memcpy(&c->operand[write_pos], &msg[read_pos],
1037                                es_info_length);
1038                         read_pos += es_info_length;
1039                         write_pos += es_info_length;
1040                 }
1041         }
1042
1043         /* CRC */
1044         c->operand[write_pos++] = 0x00;
1045         c->operand[write_pos++] = 0x00;
1046         c->operand[write_pos++] = 0x00;
1047         c->operand[write_pos++] = 0x00;
1048
1049         c->operand[7] = write_pos - 8;
1050         c->operand[12] = write_pos - 13;
1051
1052         crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
1053         c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
1054         c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
1055         c->operand[write_pos - 2] = (crc32_csum >>  8) & 0xff;
1056         c->operand[write_pos - 1] = (crc32_csum >>  0) & 0xff;
1057
1058         c->length = ALIGN(3 + write_pos, 4);
1059
1060         if (avc_write(fdtv, c, r) < 0)
1061                 return -EIO;
1062
1063         if (r->response != AVC_RESPONSE_ACCEPTED) {
1064                 dev_err(fdtv->device,
1065                         "CA PMT failed with response 0x%x\n", r->response);
1066                 return -EFAULT;
1067         }
1068
1069         return 0;
1070 }
1071
1072 int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
1073 {
1074         char buffer[sizeof(struct avc_command_frame)];
1075         struct avc_command_frame *c = (void *)buffer;
1076         struct avc_response_frame *r = (void *)buffer;
1077
1078         memset(c, 0, sizeof(*c));
1079
1080         c->ctype   = AVC_CTYPE_STATUS;
1081         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1082         c->opcode  = AVC_OPCODE_VENDOR;
1083
1084         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1085         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1086         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1087         c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1088         c->operand[4] = 0; /* slot */
1089         c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
1090         c->operand[6] = 0; /* more/last */
1091         c->operand[7] = 0; /* length */
1092
1093         c->length = 12;
1094
1095         if (avc_write(fdtv, c, r) < 0)
1096                 return -EIO;
1097
1098         /* FIXME: check response code and validate response data */
1099
1100         *interval = r->operand[get_ca_object_pos(r)];
1101
1102         return 0;
1103 }
1104
1105 int avc_ca_enter_menu(struct firedtv *fdtv)
1106 {
1107         char buffer[sizeof(struct avc_command_frame)];
1108         struct avc_command_frame *c = (void *)buffer;
1109         struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
1110
1111         memset(c, 0, sizeof(*c));
1112
1113         c->ctype   = AVC_CTYPE_STATUS;
1114         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1115         c->opcode  = AVC_OPCODE_VENDOR;
1116
1117         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1118         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1119         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1120         c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
1121         c->operand[4] = 0; /* slot */
1122         c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
1123         c->operand[6] = 0; /* more/last */
1124         c->operand[7] = 0; /* length */
1125
1126         c->length = 12;
1127
1128         if (avc_write(fdtv, c, r) < 0)
1129                 return -EIO;
1130
1131         return 0;
1132 }
1133
1134 int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
1135 {
1136         char buffer[sizeof(struct avc_command_frame)];
1137         struct avc_command_frame *c = (void *)buffer;
1138         struct avc_response_frame *r = (void *)buffer;
1139
1140         memset(c, 0, sizeof(*c));
1141
1142         c->ctype   = AVC_CTYPE_STATUS;
1143         c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
1144         c->opcode  = AVC_OPCODE_VENDOR;
1145
1146         c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
1147         c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
1148         c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
1149         c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
1150         c->operand[4] = 0; /* slot */
1151         c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
1152         c->operand[6] = 0; /* more/last */
1153         c->operand[7] = 0; /* length */
1154
1155         c->length = 12;
1156
1157         if (avc_write(fdtv, c, r) < 0)
1158                 return -EIO;
1159
1160         /* FIXME: check response code and validate response data */
1161
1162         *len = get_ca_object_length(r);
1163         memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
1164
1165         return 0;
1166 }
1167
1168 #define CMP_OUTPUT_PLUG_CONTROL_REG_0   0xfffff0000904ULL
1169
1170 static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
1171 {
1172         int ret;
1173
1174         if (mutex_lock_interruptible(&fdtv->avc_mutex))
1175                 return -EINTR;
1176
1177         ret = fdtv->backend->read(fdtv, addr, buf, len);
1178         if (ret < 0)
1179                 dev_err(fdtv->device, "CMP: read I/O error\n");
1180
1181         mutex_unlock(&fdtv->avc_mutex);
1182         return ret;
1183 }
1184
1185 static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg)
1186 {
1187         int ret;
1188
1189         if (mutex_lock_interruptible(&fdtv->avc_mutex))
1190                 return -EINTR;
1191
1192         ret = fdtv->backend->lock(fdtv, addr, data, arg);
1193         if (ret < 0)
1194                 dev_err(fdtv->device, "CMP: lock I/O error\n");
1195
1196         mutex_unlock(&fdtv->avc_mutex);
1197         return ret;
1198 }
1199
1200 static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
1201 {
1202         return (be32_to_cpu(opcr) >> shift) & mask;
1203 }
1204
1205 static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
1206 {
1207         *opcr &= ~cpu_to_be32(mask << shift);
1208         *opcr |= cpu_to_be32((value & mask) << shift);
1209 }
1210
1211 #define get_opcr_online(v)              get_opcr((v), 0x1, 31)
1212 #define get_opcr_p2p_connections(v)     get_opcr((v), 0x3f, 24)
1213 #define get_opcr_channel(v)             get_opcr((v), 0x3f, 16)
1214
1215 #define set_opcr_p2p_connections(p, v)  set_opcr((p), (v), 0x3f, 24)
1216 #define set_opcr_channel(p, v)          set_opcr((p), (v), 0x3f, 16)
1217 #define set_opcr_data_rate(p, v)        set_opcr((p), (v), 0x3, 14)
1218 #define set_opcr_overhead_id(p, v)      set_opcr((p), (v), 0xf, 10)
1219
1220 int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
1221 {
1222         __be32 old_opcr, opcr;
1223         u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1224         int attempts = 0;
1225         int ret;
1226
1227         ret = cmp_read(fdtv, &opcr, opcr_address, 4);
1228         if (ret < 0)
1229                 return ret;
1230
1231 repeat:
1232         if (!get_opcr_online(opcr)) {
1233                 dev_err(fdtv->device, "CMP: output offline\n");
1234                 return -EBUSY;
1235         }
1236
1237         old_opcr = opcr;
1238
1239         if (get_opcr_p2p_connections(opcr)) {
1240                 if (get_opcr_channel(opcr) != channel) {
1241                         dev_err(fdtv->device, "CMP: cannot change channel\n");
1242                         return -EBUSY;
1243                 }
1244                 dev_info(fdtv->device, "CMP: overlaying connection\n");
1245
1246                 /* We don't allocate isochronous resources. */
1247         } else {
1248                 set_opcr_channel(&opcr, channel);
1249                 set_opcr_data_rate(&opcr, 2); /* S400 */
1250
1251                 /* FIXME: this is for the worst case - optimize */
1252                 set_opcr_overhead_id(&opcr, 0);
1253
1254                 /*
1255                  * FIXME: allocate isochronous channel and bandwidth at IRM
1256                  * fdtv->backend->alloc_resources(fdtv, channels_mask, bw);
1257                  */
1258         }
1259
1260         set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
1261
1262         ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr);
1263         if (ret < 0)
1264                 return ret;
1265
1266         if (old_opcr != opcr) {
1267                 /*
1268                  * FIXME: if old_opcr.P2P_Connections > 0,
1269                  * deallocate isochronous channel and bandwidth at IRM
1270                  * if (...)
1271                  *      fdtv->backend->dealloc_resources(fdtv, channel, bw);
1272                  */
1273
1274                 if (++attempts < 6) /* arbitrary limit */
1275                         goto repeat;
1276                 return -EBUSY;
1277         }
1278
1279         return 0;
1280 }
1281
1282 void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
1283 {
1284         __be32 old_opcr, opcr;
1285         u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
1286         int attempts = 0;
1287
1288         if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0)
1289                 return;
1290
1291 repeat:
1292         if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
1293             get_opcr_channel(opcr) != channel) {
1294                 dev_err(fdtv->device, "CMP: no connection to break\n");
1295                 return;
1296         }
1297
1298         old_opcr = opcr;
1299         set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
1300
1301         if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0)
1302                 return;
1303
1304         if (old_opcr != opcr) {
1305                 /*
1306                  * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
1307                  * owner, deallocate isochronous channel and bandwidth at IRM
1308                  * if (...)
1309                  *      fdtv->backend->dealloc_resources(fdtv, channel, bw);
1310                  */
1311
1312                 if (++attempts < 6) /* arbitrary limit */
1313                         goto repeat;
1314         }
1315 }