2 * FireDTV driver (formerly known as FireSAT)
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>
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.
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>
29 #define FCP_COMMAND_REGISTER 0xfffff0000b00ULL
31 #define AVC_CTYPE_CONTROL 0x0
32 #define AVC_CTYPE_STATUS 0x1
33 #define AVC_CTYPE_NOTIFY 0x3
35 #define AVC_RESPONSE_ACCEPTED 0x9
36 #define AVC_RESPONSE_STABLE 0xc
37 #define AVC_RESPONSE_CHANGED 0xd
38 #define AVC_RESPONSE_INTERIM 0xf
40 #define AVC_SUBUNIT_TYPE_TUNER (0x05 << 3)
41 #define AVC_SUBUNIT_TYPE_UNIT (0x1f << 3)
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
48 #define DESCRIPTOR_TUNER_STATUS 0x80
49 #define DESCRIPTOR_SUBUNIT_IDENTIFIER 0x00
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
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 */
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 */
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
72 #define EN50221_LIST_MANAGEMENT_ONLY 0x03
73 #define EN50221_TAG_APP_INFO 0x9f8021
74 #define EN50221_TAG_CA_INFO 0x9f8031
76 struct avc_command_frame
{
84 struct avc_response_frame
{
92 #define AVC_DEBUG_FCP_SUBACTIONS 1
93 #define AVC_DEBUG_FCP_PAYLOADS 2
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
)
102 static const char *debug_fcp_ctype(unsigned int ctype
)
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",
112 const char *ret
= ctype
< ARRAY_SIZE(ctypes
) ? ctypes
[ctype
] : NULL
;
114 return ret
? ret
: "?";
117 static const char *debug_fcp_opcode(unsigned int opcode
,
118 const u8
*data
, int length
)
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";
129 data
[3] != SFE_VENDOR_DE_COMPANYID_0
||
130 data
[4] != SFE_VENDOR_DE_COMPANYID_1
||
131 data
[5] != SFE_VENDOR_DE_COMPANYID_2
)
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_TUNE_QPSK2
: return "TuneQPSK2";
139 case SFE_VENDOR_OPCODE_HOST2CA
: return "Host2CA";
140 case SFE_VENDOR_OPCODE_CA2HOST
: return "CA2Host";
145 static void debug_fcp(const u8
*data
, int length
)
147 unsigned int subunit_type
, subunit_id
, op
;
148 const char *prefix
= data
[0] > 7 ? "FCP <- " : "FCP -> ";
150 if (avc_debug
& AVC_DEBUG_FCP_SUBACTIONS
) {
151 subunit_type
= data
[1] >> 3;
152 subunit_id
= data
[1] & 7;
153 op
= subunit_type
== 0x1e || subunit_id
== 5 ? ~0 : data
[2];
154 printk(KERN_INFO
"%ssu=%x.%x l=%d: %-8s - %s\n",
155 prefix
, subunit_type
, subunit_id
, length
,
156 debug_fcp_ctype(data
[0]),
157 debug_fcp_opcode(op
, data
, length
));
160 if (avc_debug
& AVC_DEBUG_FCP_PAYLOADS
)
161 print_hex_dump(KERN_INFO
, prefix
, DUMP_PREFIX_NONE
, 16, 1,
162 data
, length
, false);
165 static int __avc_write(struct firedtv
*fdtv
,
166 const struct avc_command_frame
*c
, struct avc_response_frame
*r
)
171 fdtv
->avc_reply_received
= false;
173 for (retry
= 0; retry
< 6; retry
++) {
174 if (unlikely(avc_debug
))
175 debug_fcp(&c
->ctype
, c
->length
);
177 err
= fdtv
->backend
->write(fdtv
, FCP_COMMAND_REGISTER
,
178 (void *)&c
->ctype
, c
->length
);
180 fdtv
->avc_reply_received
= true;
181 dev_err(fdtv
->device
, "FCP command write failed\n");
189 * AV/C specs say that answers should be sent within 150 ms.
190 * Time out after 200 ms.
192 if (wait_event_timeout(fdtv
->avc_wait
,
193 fdtv
->avc_reply_received
,
194 msecs_to_jiffies(200)) != 0) {
195 r
->length
= fdtv
->response_length
;
196 memcpy(&r
->response
, fdtv
->response
, r
->length
);
201 dev_err(fdtv
->device
, "FCP response timed out\n");
205 static int avc_write(struct firedtv
*fdtv
,
206 const struct avc_command_frame
*c
, struct avc_response_frame
*r
)
210 if (mutex_lock_interruptible(&fdtv
->avc_mutex
))
213 ret
= __avc_write(fdtv
, c
, r
);
215 mutex_unlock(&fdtv
->avc_mutex
);
219 int avc_recv(struct firedtv
*fdtv
, void *data
, size_t length
)
221 struct avc_response_frame
*r
=
222 data
- offsetof(struct avc_response_frame
, response
);
224 if (unlikely(avc_debug
))
225 debug_fcp(data
, length
);
228 r
->operand
[0] == SFE_VENDOR_DE_COMPANYID_0
&&
229 r
->operand
[1] == SFE_VENDOR_DE_COMPANYID_1
&&
230 r
->operand
[2] == SFE_VENDOR_DE_COMPANYID_2
&&
231 r
->operand
[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL
) {
232 if (r
->response
== AVC_RESPONSE_CHANGED
) {
234 r
->operand
[4] << 8 | r
->operand
[5]);
235 schedule_work(&fdtv
->remote_ctrl_work
);
236 } else if (r
->response
!= AVC_RESPONSE_INTERIM
) {
237 dev_info(fdtv
->device
,
238 "remote control result = %d\n", r
->response
);
243 if (fdtv
->avc_reply_received
) {
244 dev_err(fdtv
->device
, "out-of-order AVC response, ignored\n");
248 memcpy(fdtv
->response
, data
, length
);
249 fdtv
->response_length
= length
;
251 fdtv
->avc_reply_received
= true;
252 wake_up(&fdtv
->avc_wait
);
258 * tuning command for setting the relative LNB frequency
259 * (not supported by the AVC standard)
261 static void avc_tuner_tuneqpsk(struct firedtv
*fdtv
,
262 struct dvb_frontend_parameters
*params
,
263 struct avc_command_frame
*c
)
265 c
->opcode
= AVC_OPCODE_VENDOR
;
267 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
268 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
269 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
270 if (fdtv
->type
== FIREDTV_DVB_S2
)
271 c
->operand
[3] = SFE_VENDOR_OPCODE_TUNE_QPSK2
;
273 c
->operand
[3] = SFE_VENDOR_OPCODE_TUNE_QPSK
;
275 c
->operand
[4] = (params
->frequency
>> 24) & 0xff;
276 c
->operand
[5] = (params
->frequency
>> 16) & 0xff;
277 c
->operand
[6] = (params
->frequency
>> 8) & 0xff;
278 c
->operand
[7] = params
->frequency
& 0xff;
280 c
->operand
[8] = ((params
->u
.qpsk
.symbol_rate
/ 1000) >> 8) & 0xff;
281 c
->operand
[9] = (params
->u
.qpsk
.symbol_rate
/ 1000) & 0xff;
283 switch (params
->u
.qpsk
.fec_inner
) {
284 case FEC_1_2
: c
->operand
[10] = 0x1; break;
285 case FEC_2_3
: c
->operand
[10] = 0x2; break;
286 case FEC_3_4
: c
->operand
[10] = 0x3; break;
287 case FEC_5_6
: c
->operand
[10] = 0x4; break;
288 case FEC_7_8
: c
->operand
[10] = 0x5; break;
292 default: c
->operand
[10] = 0x0;
295 if (fdtv
->voltage
== 0xff)
296 c
->operand
[11] = 0xff;
297 else if (fdtv
->voltage
== SEC_VOLTAGE_18
) /* polarisation */
302 if (fdtv
->tone
== 0xff)
303 c
->operand
[12] = 0xff;
304 else if (fdtv
->tone
== SEC_TONE_ON
) /* band */
309 if (fdtv
->type
== FIREDTV_DVB_S2
) {
310 c
->operand
[13] = 0x1;
311 c
->operand
[14] = 0xff;
312 c
->operand
[15] = 0xff;
319 static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters
*params
,
320 struct avc_command_frame
*c
)
322 c
->opcode
= AVC_OPCODE_DSD
;
324 c
->operand
[0] = 0; /* source plug */
325 c
->operand
[1] = 0xd2; /* subfunction replace */
326 c
->operand
[2] = 0x20; /* system id = DVB */
327 c
->operand
[3] = 0x00; /* antenna number */
328 c
->operand
[4] = 0x11; /* system_specific_multiplex selection_length */
330 /* multiplex_valid_flags, high byte */
331 c
->operand
[5] = 0 << 7 /* reserved */
332 | 0 << 6 /* Polarisation */
333 | 0 << 5 /* Orbital_Pos */
334 | 1 << 4 /* Frequency */
335 | 1 << 3 /* Symbol_Rate */
336 | 0 << 2 /* FEC_outer */
337 | (params
->u
.qam
.fec_inner
!= FEC_AUTO
? 1 << 1 : 0)
338 | (params
->u
.qam
.modulation
!= QAM_AUTO
? 1 << 0 : 0);
340 /* multiplex_valid_flags, low byte */
341 c
->operand
[6] = 0 << 7 /* NetworkID */
342 | 0 << 0 /* reserved */ ;
344 c
->operand
[7] = 0x00;
345 c
->operand
[8] = 0x00;
346 c
->operand
[9] = 0x00;
347 c
->operand
[10] = 0x00;
349 c
->operand
[11] = (((params
->frequency
/ 4000) >> 16) & 0xff) | (2 << 6);
350 c
->operand
[12] = ((params
->frequency
/ 4000) >> 8) & 0xff;
351 c
->operand
[13] = (params
->frequency
/ 4000) & 0xff;
352 c
->operand
[14] = ((params
->u
.qpsk
.symbol_rate
/ 1000) >> 12) & 0xff;
353 c
->operand
[15] = ((params
->u
.qpsk
.symbol_rate
/ 1000) >> 4) & 0xff;
354 c
->operand
[16] = ((params
->u
.qpsk
.symbol_rate
/ 1000) << 4) & 0xf0;
355 c
->operand
[17] = 0x00;
357 switch (params
->u
.qpsk
.fec_inner
) {
358 case FEC_1_2
: c
->operand
[18] = 0x1; break;
359 case FEC_2_3
: c
->operand
[18] = 0x2; break;
360 case FEC_3_4
: c
->operand
[18] = 0x3; break;
361 case FEC_5_6
: c
->operand
[18] = 0x4; break;
362 case FEC_7_8
: c
->operand
[18] = 0x5; break;
363 case FEC_8_9
: c
->operand
[18] = 0x6; break;
364 case FEC_4_5
: c
->operand
[18] = 0x8; break;
366 default: c
->operand
[18] = 0x0;
369 switch (params
->u
.qam
.modulation
) {
370 case QAM_16
: c
->operand
[19] = 0x08; break;
371 case QAM_32
: c
->operand
[19] = 0x10; break;
372 case QAM_64
: c
->operand
[19] = 0x18; break;
373 case QAM_128
: c
->operand
[19] = 0x20; break;
374 case QAM_256
: c
->operand
[19] = 0x28; break;
376 default: c
->operand
[19] = 0x00;
379 c
->operand
[20] = 0x00;
380 c
->operand
[21] = 0x00;
381 /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
382 c
->operand
[22] = 0x00;
387 static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters
*params
,
388 struct avc_command_frame
*c
)
390 struct dvb_ofdm_parameters
*ofdm
= ¶ms
->u
.ofdm
;
392 c
->opcode
= AVC_OPCODE_DSD
;
394 c
->operand
[0] = 0; /* source plug */
395 c
->operand
[1] = 0xd2; /* subfunction replace */
396 c
->operand
[2] = 0x20; /* system id = DVB */
397 c
->operand
[3] = 0x00; /* antenna number */
398 c
->operand
[4] = 0x0c; /* system_specific_multiplex selection_length */
400 /* multiplex_valid_flags, high byte */
402 0 << 7 /* reserved */
403 | 1 << 6 /* CenterFrequency */
404 | (ofdm
->bandwidth
!= BANDWIDTH_AUTO
? 1 << 5 : 0)
405 | (ofdm
->constellation
!= QAM_AUTO
? 1 << 4 : 0)
406 | (ofdm
->hierarchy_information
!= HIERARCHY_AUTO
? 1 << 3 : 0)
407 | (ofdm
->code_rate_HP
!= FEC_AUTO
? 1 << 2 : 0)
408 | (ofdm
->code_rate_LP
!= FEC_AUTO
? 1 << 1 : 0)
409 | (ofdm
->guard_interval
!= GUARD_INTERVAL_AUTO
? 1 << 0 : 0);
411 /* multiplex_valid_flags, low byte */
413 0 << 7 /* NetworkID */
414 | (ofdm
->transmission_mode
!= TRANSMISSION_MODE_AUTO
? 1 << 6 : 0)
415 | 0 << 5 /* OtherFrequencyFlag */
416 | 0 << 0 /* reserved */ ;
419 c
->operand
[8] = (params
->frequency
/ 10) >> 24;
420 c
->operand
[9] = ((params
->frequency
/ 10) >> 16) & 0xff;
421 c
->operand
[10] = ((params
->frequency
/ 10) >> 8) & 0xff;
422 c
->operand
[11] = (params
->frequency
/ 10) & 0xff;
424 switch (ofdm
->bandwidth
) {
425 case BANDWIDTH_7_MHZ
: c
->operand
[12] = 0x20; break;
426 case BANDWIDTH_8_MHZ
:
427 case BANDWIDTH_6_MHZ
: /* not defined by AVC spec */
429 default: c
->operand
[12] = 0x00;
432 switch (ofdm
->constellation
) {
433 case QAM_16
: c
->operand
[13] = 1 << 6; break;
434 case QAM_64
: c
->operand
[13] = 2 << 6; break;
436 default: c
->operand
[13] = 0x00;
439 switch (ofdm
->hierarchy_information
) {
440 case HIERARCHY_1
: c
->operand
[13] |= 1 << 3; break;
441 case HIERARCHY_2
: c
->operand
[13] |= 2 << 3; break;
442 case HIERARCHY_4
: c
->operand
[13] |= 3 << 3; break;
448 switch (ofdm
->code_rate_HP
) {
449 case FEC_2_3
: c
->operand
[13] |= 1; break;
450 case FEC_3_4
: c
->operand
[13] |= 2; break;
451 case FEC_5_6
: c
->operand
[13] |= 3; break;
452 case FEC_7_8
: c
->operand
[13] |= 4; break;
457 switch (ofdm
->code_rate_LP
) {
458 case FEC_2_3
: c
->operand
[14] = 1 << 5; break;
459 case FEC_3_4
: c
->operand
[14] = 2 << 5; break;
460 case FEC_5_6
: c
->operand
[14] = 3 << 5; break;
461 case FEC_7_8
: c
->operand
[14] = 4 << 5; break;
463 default: c
->operand
[14] = 0x00; break;
466 switch (ofdm
->guard_interval
) {
467 case GUARD_INTERVAL_1_16
: c
->operand
[14] |= 1 << 3; break;
468 case GUARD_INTERVAL_1_8
: c
->operand
[14] |= 2 << 3; break;
469 case GUARD_INTERVAL_1_4
: c
->operand
[14] |= 3 << 3; break;
470 case GUARD_INTERVAL_1_32
:
471 case GUARD_INTERVAL_AUTO
:
475 switch (ofdm
->transmission_mode
) {
476 case TRANSMISSION_MODE_8K
: c
->operand
[14] |= 1 << 1; break;
477 case TRANSMISSION_MODE_2K
:
478 case TRANSMISSION_MODE_AUTO
:
482 c
->operand
[15] = 0x00; /* network_ID[0] */
483 c
->operand
[16] = 0x00; /* network_ID[1] */
484 /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
485 c
->operand
[17] = 0x00;
490 int avc_tuner_dsd(struct firedtv
*fdtv
,
491 struct dvb_frontend_parameters
*params
)
493 char buffer
[sizeof(struct avc_command_frame
)];
494 struct avc_command_frame
*c
= (void *)buffer
;
495 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
497 memset(c
, 0, sizeof(*c
));
499 c
->ctype
= AVC_CTYPE_CONTROL
;
500 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
502 switch (fdtv
->type
) {
504 case FIREDTV_DVB_S2
: avc_tuner_tuneqpsk(fdtv
, params
, c
); break;
505 case FIREDTV_DVB_C
: avc_tuner_dsd_dvb_c(params
, c
); break;
506 case FIREDTV_DVB_T
: avc_tuner_dsd_dvb_t(params
, c
); break;
511 if (avc_write(fdtv
, c
, r
) < 0)
517 /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
519 *status
= r
->operand
[2];
524 int avc_tuner_set_pids(struct firedtv
*fdtv
, unsigned char pidc
, u16 pid
[])
526 char buffer
[sizeof(struct avc_command_frame
)];
527 struct avc_command_frame
*c
= (void *)buffer
;
528 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
531 if (pidc
> 16 && pidc
!= 0xff)
534 memset(c
, 0, sizeof(*c
));
536 c
->ctype
= AVC_CTYPE_CONTROL
;
537 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
538 c
->opcode
= AVC_OPCODE_DSD
;
540 c
->operand
[0] = 0; /* source plug */
541 c
->operand
[1] = 0xd2; /* subfunction replace */
542 c
->operand
[2] = 0x20; /* system id = DVB */
543 c
->operand
[3] = 0x00; /* antenna number */
544 c
->operand
[4] = 0x00; /* system_specific_multiplex selection_length */
545 c
->operand
[5] = pidc
; /* Nr_of_dsd_sel_specs */
549 for (k
= 0; k
< pidc
; k
++) {
550 c
->operand
[pos
++] = 0x13; /* flowfunction relay */
551 c
->operand
[pos
++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
552 c
->operand
[pos
++] = (pid
[k
] >> 8) & 0x1f;
553 c
->operand
[pos
++] = pid
[k
] & 0xff;
554 c
->operand
[pos
++] = 0x00; /* tableID */
555 c
->operand
[pos
++] = 0x00; /* filter_length */
558 c
->length
= ALIGN(3 + pos
, 4);
560 if (avc_write(fdtv
, c
, r
) < 0)
567 int avc_tuner_get_ts(struct firedtv
*fdtv
)
569 char buffer
[sizeof(struct avc_command_frame
)];
570 struct avc_command_frame
*c
= (void *)buffer
;
571 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
574 memset(c
, 0, sizeof(*c
));
576 c
->ctype
= AVC_CTYPE_CONTROL
;
577 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
578 c
->opcode
= AVC_OPCODE_DSIT
;
580 sl
= fdtv
->type
== FIREDTV_DVB_T
? 0x0c : 0x11;
582 c
->operand
[0] = 0; /* source plug */
583 c
->operand
[1] = 0xd2; /* subfunction replace */
584 c
->operand
[2] = 0xff; /* status */
585 c
->operand
[3] = 0x20; /* system id = DVB */
586 c
->operand
[4] = 0x00; /* antenna number */
587 c
->operand
[5] = 0x0; /* system_specific_search_flags */
588 c
->operand
[6] = sl
; /* system_specific_multiplex selection_length */
589 c
->operand
[7] = 0x00; /* valid_flags [0] */
590 c
->operand
[8] = 0x00; /* valid_flags [1] */
591 c
->operand
[7 + sl
] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
593 c
->length
= fdtv
->type
== FIREDTV_DVB_T
? 24 : 28;
595 if (avc_write(fdtv
, c
, r
) < 0)
602 int avc_identify_subunit(struct firedtv
*fdtv
)
604 char buffer
[sizeof(struct avc_command_frame
)];
605 struct avc_command_frame
*c
= (void *)buffer
;
606 struct avc_response_frame
*r
= (void *)buffer
;
608 memset(c
, 0, sizeof(*c
));
610 c
->ctype
= AVC_CTYPE_CONTROL
;
611 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
612 c
->opcode
= AVC_OPCODE_READ_DESCRIPTOR
;
614 c
->operand
[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER
;
615 c
->operand
[1] = 0xff;
616 c
->operand
[2] = 0x00;
617 c
->operand
[3] = 0x00; /* length highbyte */
618 c
->operand
[4] = 0x08; /* length lowbyte */
619 c
->operand
[5] = 0x00; /* offset highbyte */
620 c
->operand
[6] = 0x0d; /* offset lowbyte */
624 if (avc_write(fdtv
, c
, r
) < 0)
627 if ((r
->response
!= AVC_RESPONSE_STABLE
&&
628 r
->response
!= AVC_RESPONSE_ACCEPTED
) ||
629 (r
->operand
[3] << 8) + r
->operand
[4] != 8) {
630 dev_err(fdtv
->device
, "cannot read subunit identifier\n");
636 #define SIZEOF_ANTENNA_INPUT_INFO 22
638 int avc_tuner_status(struct firedtv
*fdtv
, struct firedtv_tuner_status
*stat
)
640 char buffer
[sizeof(struct avc_command_frame
)];
641 struct avc_command_frame
*c
= (void *)buffer
;
642 struct avc_response_frame
*r
= (void *)buffer
;
645 memset(c
, 0, sizeof(*c
));
647 c
->ctype
= AVC_CTYPE_CONTROL
;
648 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
649 c
->opcode
= AVC_OPCODE_READ_DESCRIPTOR
;
651 c
->operand
[0] = DESCRIPTOR_TUNER_STATUS
;
652 c
->operand
[1] = 0xff; /* read_result_status */
653 c
->operand
[2] = 0x00; /* reserved */
654 c
->operand
[3] = 0; /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
655 c
->operand
[4] = 0; /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
656 c
->operand
[5] = 0x00;
657 c
->operand
[6] = 0x00;
661 if (avc_write(fdtv
, c
, r
) < 0)
664 if (r
->response
!= AVC_RESPONSE_STABLE
&&
665 r
->response
!= AVC_RESPONSE_ACCEPTED
) {
666 dev_err(fdtv
->device
, "cannot read tuner status\n");
670 length
= r
->operand
[9];
671 if (r
->operand
[1] != 0x10 || length
!= SIZEOF_ANTENNA_INPUT_INFO
) {
672 dev_err(fdtv
->device
, "got invalid tuner status\n");
676 stat
->active_system
= r
->operand
[10];
677 stat
->searching
= r
->operand
[11] >> 7 & 1;
678 stat
->moving
= r
->operand
[11] >> 6 & 1;
679 stat
->no_rf
= r
->operand
[11] >> 5 & 1;
680 stat
->input
= r
->operand
[12] >> 7 & 1;
681 stat
->selected_antenna
= r
->operand
[12] & 0x7f;
682 stat
->ber
= r
->operand
[13] << 24 |
683 r
->operand
[14] << 16 |
684 r
->operand
[15] << 8 |
686 stat
->signal_strength
= r
->operand
[17];
687 stat
->raster_frequency
= r
->operand
[18] >> 6 & 2;
688 stat
->rf_frequency
= (r
->operand
[18] & 0x3f) << 16 |
689 r
->operand
[19] << 8 |
691 stat
->man_dep_info_length
= r
->operand
[21];
692 stat
->front_end_error
= r
->operand
[22] >> 4 & 1;
693 stat
->antenna_error
= r
->operand
[22] >> 3 & 1;
694 stat
->front_end_power_status
= r
->operand
[22] >> 1 & 1;
695 stat
->power_supply
= r
->operand
[22] & 1;
696 stat
->carrier_noise_ratio
= r
->operand
[23] << 8 |
698 stat
->power_supply_voltage
= r
->operand
[27];
699 stat
->antenna_voltage
= r
->operand
[28];
700 stat
->firewire_bus_voltage
= r
->operand
[29];
701 stat
->ca_mmi
= r
->operand
[30] & 1;
702 stat
->ca_pmt_reply
= r
->operand
[31] >> 7 & 1;
703 stat
->ca_date_time_request
= r
->operand
[31] >> 6 & 1;
704 stat
->ca_application_info
= r
->operand
[31] >> 5 & 1;
705 stat
->ca_module_present_status
= r
->operand
[31] >> 4 & 1;
706 stat
->ca_dvb_flag
= r
->operand
[31] >> 3 & 1;
707 stat
->ca_error_flag
= r
->operand
[31] >> 2 & 1;
708 stat
->ca_initialization_status
= r
->operand
[31] >> 1 & 1;
713 int avc_lnb_control(struct firedtv
*fdtv
, char voltage
, char burst
,
714 char conttone
, char nrdiseq
,
715 struct dvb_diseqc_master_cmd
*diseqcmd
)
717 char buffer
[sizeof(struct avc_command_frame
)];
718 struct avc_command_frame
*c
= (void *)buffer
;
719 struct avc_response_frame
*r
= (void *)buffer
;
722 memset(c
, 0, sizeof(*c
));
724 c
->ctype
= AVC_CTYPE_CONTROL
;
725 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
726 c
->opcode
= AVC_OPCODE_VENDOR
;
728 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
729 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
730 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
731 c
->operand
[3] = SFE_VENDOR_OPCODE_LNB_CONTROL
;
733 c
->operand
[4] = voltage
;
734 c
->operand
[5] = nrdiseq
;
738 for (j
= 0; j
< nrdiseq
; j
++) {
739 c
->operand
[i
++] = diseqcmd
[j
].msg_len
;
741 for (k
= 0; k
< diseqcmd
[j
].msg_len
; k
++)
742 c
->operand
[i
++] = diseqcmd
[j
].msg
[k
];
745 c
->operand
[i
++] = burst
;
746 c
->operand
[i
++] = conttone
;
748 c
->length
= ALIGN(3 + i
, 4);
750 if (avc_write(fdtv
, c
, r
) < 0)
753 if (r
->response
!= AVC_RESPONSE_ACCEPTED
) {
754 dev_err(fdtv
->device
, "LNB control failed\n");
761 int avc_register_remote_control(struct firedtv
*fdtv
)
763 char buffer
[sizeof(struct avc_command_frame
)];
764 struct avc_command_frame
*c
= (void *)buffer
;
766 memset(c
, 0, sizeof(*c
));
768 c
->ctype
= AVC_CTYPE_NOTIFY
;
769 c
->subunit
= AVC_SUBUNIT_TYPE_UNIT
| 7;
770 c
->opcode
= AVC_OPCODE_VENDOR
;
772 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
773 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
774 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
775 c
->operand
[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL
;
779 return avc_write(fdtv
, c
, NULL
);
782 void avc_remote_ctrl_work(struct work_struct
*work
)
784 struct firedtv
*fdtv
=
785 container_of(work
, struct firedtv
, remote_ctrl_work
);
787 /* Should it be rescheduled in failure cases? */
788 avc_register_remote_control(fdtv
);
791 #if 0 /* FIXME: unused */
792 int avc_tuner_host2ca(struct firedtv
*fdtv
)
794 char buffer
[sizeof(struct avc_command_frame
)];
795 struct avc_command_frame
*c
= (void *)buffer
;
796 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
798 memset(c
, 0, sizeof(*c
));
800 c
->ctype
= AVC_CTYPE_CONTROL
;
801 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
802 c
->opcode
= AVC_OPCODE_VENDOR
;
804 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
805 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
806 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
807 c
->operand
[3] = SFE_VENDOR_OPCODE_HOST2CA
;
808 c
->operand
[4] = 0; /* slot */
809 c
->operand
[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO
; /* ca tag */
810 c
->operand
[6] = 0; /* more/last */
811 c
->operand
[7] = 0; /* length */
815 if (avc_write(fdtv
, c
, r
) < 0)
822 static int get_ca_object_pos(struct avc_response_frame
*r
)
826 /* Check length of length field */
827 if (r
->operand
[7] & 0x80)
828 length
= (r
->operand
[7] & 0x7f) + 1;
832 static int get_ca_object_length(struct avc_response_frame
*r
)
834 #if 0 /* FIXME: unused */
838 if (r
->operand
[7] & 0x80)
839 for (i
= 0; i
< (r
->operand
[7] & 0x7f); i
++) {
841 size
+= r
->operand
[8 + i
];
844 return r
->operand
[7];
847 int avc_ca_app_info(struct firedtv
*fdtv
, char *app_info
, unsigned int *len
)
849 char buffer
[sizeof(struct avc_command_frame
)];
850 struct avc_command_frame
*c
= (void *)buffer
;
851 struct avc_response_frame
*r
= (void *)buffer
;
854 memset(c
, 0, sizeof(*c
));
856 c
->ctype
= AVC_CTYPE_STATUS
;
857 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
858 c
->opcode
= AVC_OPCODE_VENDOR
;
860 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
861 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
862 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
863 c
->operand
[3] = SFE_VENDOR_OPCODE_CA2HOST
;
864 c
->operand
[4] = 0; /* slot */
865 c
->operand
[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO
; /* ca tag */
869 if (avc_write(fdtv
, c
, r
) < 0)
872 /* FIXME: check response code and validate response data */
874 pos
= get_ca_object_pos(r
);
875 app_info
[0] = (EN50221_TAG_APP_INFO
>> 16) & 0xff;
876 app_info
[1] = (EN50221_TAG_APP_INFO
>> 8) & 0xff;
877 app_info
[2] = (EN50221_TAG_APP_INFO
>> 0) & 0xff;
878 app_info
[3] = 6 + r
->operand
[pos
+ 4];
880 memcpy(&app_info
[5], &r
->operand
[pos
], 5 + r
->operand
[pos
+ 4]);
881 *len
= app_info
[3] + 4;
886 int avc_ca_info(struct firedtv
*fdtv
, char *app_info
, unsigned int *len
)
888 char buffer
[sizeof(struct avc_command_frame
)];
889 struct avc_command_frame
*c
= (void *)buffer
;
890 struct avc_response_frame
*r
= (void *)buffer
;
893 memset(c
, 0, sizeof(*c
));
895 c
->ctype
= AVC_CTYPE_STATUS
;
896 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
897 c
->opcode
= AVC_OPCODE_VENDOR
;
899 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
900 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
901 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
902 c
->operand
[3] = SFE_VENDOR_OPCODE_CA2HOST
;
903 c
->operand
[4] = 0; /* slot */
904 c
->operand
[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO
; /* ca tag */
908 if (avc_write(fdtv
, c
, r
) < 0)
911 pos
= get_ca_object_pos(r
);
912 app_info
[0] = (EN50221_TAG_CA_INFO
>> 16) & 0xff;
913 app_info
[1] = (EN50221_TAG_CA_INFO
>> 8) & 0xff;
914 app_info
[2] = (EN50221_TAG_CA_INFO
>> 0) & 0xff;
916 app_info
[4] = r
->operand
[pos
+ 0];
917 app_info
[5] = r
->operand
[pos
+ 1];
918 *len
= app_info
[3] + 4;
923 int avc_ca_reset(struct firedtv
*fdtv
)
925 char buffer
[sizeof(struct avc_command_frame
)];
926 struct avc_command_frame
*c
= (void *)buffer
;
927 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
929 memset(c
, 0, sizeof(*c
));
931 c
->ctype
= AVC_CTYPE_CONTROL
;
932 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
933 c
->opcode
= AVC_OPCODE_VENDOR
;
935 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
936 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
937 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
938 c
->operand
[3] = SFE_VENDOR_OPCODE_HOST2CA
;
939 c
->operand
[4] = 0; /* slot */
940 c
->operand
[5] = SFE_VENDOR_TAG_CA_RESET
; /* ca tag */
941 c
->operand
[6] = 0; /* more/last */
942 c
->operand
[7] = 1; /* length */
943 c
->operand
[8] = 0; /* force hardware reset */
947 if (avc_write(fdtv
, c
, r
) < 0)
953 int avc_ca_pmt(struct firedtv
*fdtv
, char *msg
, int length
)
955 char buffer
[sizeof(struct avc_command_frame
)];
956 struct avc_command_frame
*c
= (void *)buffer
;
957 struct avc_response_frame
*r
= (void *)buffer
;
959 int program_info_length
;
966 memset(c
, 0, sizeof(*c
));
968 c
->ctype
= AVC_CTYPE_CONTROL
;
969 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
970 c
->opcode
= AVC_OPCODE_VENDOR
;
972 if (msg
[0] != EN50221_LIST_MANAGEMENT_ONLY
) {
973 dev_info(fdtv
->device
, "forcing list_management to ONLY\n");
974 msg
[0] = EN50221_LIST_MANAGEMENT_ONLY
;
976 /* We take the cmd_id from the programme level only! */
977 list_management
= msg
[0];
978 program_info_length
= ((msg
[4] & 0x0f) << 8) + msg
[5];
979 if (program_info_length
> 0)
980 program_info_length
--; /* Remove pmt_cmd_id */
983 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
984 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
985 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
986 c
->operand
[3] = SFE_VENDOR_OPCODE_HOST2CA
;
987 c
->operand
[4] = 0; /* slot */
988 c
->operand
[5] = SFE_VENDOR_TAG_CA_PMT
; /* ca tag */
989 c
->operand
[6] = 0; /* more/last */
990 /* c->operand[7] = XXXprogram_info_length + 17; */ /* length */
991 c
->operand
[8] = list_management
;
992 c
->operand
[9] = 0x01; /* pmt_cmd=OK_descramble */
994 /* TS program map table */
996 c
->operand
[10] = 0x02; /* Table id=2 */
997 c
->operand
[11] = 0x80; /* Section syntax + length */
998 /* c->operand[12] = XXXprogram_info_length + 12; */
999 c
->operand
[13] = msg
[1]; /* Program number */
1000 c
->operand
[14] = msg
[2];
1001 c
->operand
[15] = 0x01; /* Version number=0 + current/next=1 */
1002 c
->operand
[16] = 0x00; /* Section number=0 */
1003 c
->operand
[17] = 0x00; /* Last section number=0 */
1004 c
->operand
[18] = 0x1f; /* PCR_PID=1FFF */
1005 c
->operand
[19] = 0xff;
1006 c
->operand
[20] = (program_info_length
>> 8); /* Program info length */
1007 c
->operand
[21] = (program_info_length
& 0xff);
1009 /* CA descriptors at programme level */
1012 if (program_info_length
> 0) {
1013 pmt_cmd_id
= msg
[read_pos
++];
1014 if (pmt_cmd_id
!= 1 && pmt_cmd_id
!= 4)
1015 dev_err(fdtv
->device
,
1016 "invalid pmt_cmd_id %d\n", pmt_cmd_id
);
1018 memcpy(&c
->operand
[write_pos
], &msg
[read_pos
],
1019 program_info_length
);
1020 read_pos
+= program_info_length
;
1021 write_pos
+= program_info_length
;
1023 while (read_pos
< length
) {
1024 c
->operand
[write_pos
++] = msg
[read_pos
++];
1025 c
->operand
[write_pos
++] = msg
[read_pos
++];
1026 c
->operand
[write_pos
++] = msg
[read_pos
++];
1028 ((msg
[read_pos
] & 0x0f) << 8) + msg
[read_pos
+ 1];
1030 if (es_info_length
> 0)
1031 es_info_length
--; /* Remove pmt_cmd_id */
1032 c
->operand
[write_pos
++] = es_info_length
>> 8;
1033 c
->operand
[write_pos
++] = es_info_length
& 0xff;
1034 if (es_info_length
> 0) {
1035 pmt_cmd_id
= msg
[read_pos
++];
1036 if (pmt_cmd_id
!= 1 && pmt_cmd_id
!= 4)
1037 dev_err(fdtv
->device
, "invalid pmt_cmd_id %d "
1038 "at stream level\n", pmt_cmd_id
);
1040 memcpy(&c
->operand
[write_pos
], &msg
[read_pos
],
1042 read_pos
+= es_info_length
;
1043 write_pos
+= es_info_length
;
1048 c
->operand
[write_pos
++] = 0x00;
1049 c
->operand
[write_pos
++] = 0x00;
1050 c
->operand
[write_pos
++] = 0x00;
1051 c
->operand
[write_pos
++] = 0x00;
1053 c
->operand
[7] = write_pos
- 8;
1054 c
->operand
[12] = write_pos
- 13;
1056 crc32_csum
= crc32_be(0, &c
->operand
[10], c
->operand
[12] - 1);
1057 c
->operand
[write_pos
- 4] = (crc32_csum
>> 24) & 0xff;
1058 c
->operand
[write_pos
- 3] = (crc32_csum
>> 16) & 0xff;
1059 c
->operand
[write_pos
- 2] = (crc32_csum
>> 8) & 0xff;
1060 c
->operand
[write_pos
- 1] = (crc32_csum
>> 0) & 0xff;
1062 c
->length
= ALIGN(3 + write_pos
, 4);
1064 if (avc_write(fdtv
, c
, r
) < 0)
1067 if (r
->response
!= AVC_RESPONSE_ACCEPTED
) {
1068 dev_err(fdtv
->device
,
1069 "CA PMT failed with response 0x%x\n", r
->response
);
1076 int avc_ca_get_time_date(struct firedtv
*fdtv
, int *interval
)
1078 char buffer
[sizeof(struct avc_command_frame
)];
1079 struct avc_command_frame
*c
= (void *)buffer
;
1080 struct avc_response_frame
*r
= (void *)buffer
;
1082 memset(c
, 0, sizeof(*c
));
1084 c
->ctype
= AVC_CTYPE_STATUS
;
1085 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
1086 c
->opcode
= AVC_OPCODE_VENDOR
;
1088 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
1089 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
1090 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
1091 c
->operand
[3] = SFE_VENDOR_OPCODE_CA2HOST
;
1092 c
->operand
[4] = 0; /* slot */
1093 c
->operand
[5] = SFE_VENDOR_TAG_CA_DATE_TIME
; /* ca tag */
1094 c
->operand
[6] = 0; /* more/last */
1095 c
->operand
[7] = 0; /* length */
1099 if (avc_write(fdtv
, c
, r
) < 0)
1102 /* FIXME: check response code and validate response data */
1104 *interval
= r
->operand
[get_ca_object_pos(r
)];
1109 int avc_ca_enter_menu(struct firedtv
*fdtv
)
1111 char buffer
[sizeof(struct avc_command_frame
)];
1112 struct avc_command_frame
*c
= (void *)buffer
;
1113 struct avc_response_frame
*r
= (void *)buffer
; /* FIXME: unused */
1115 memset(c
, 0, sizeof(*c
));
1117 c
->ctype
= AVC_CTYPE_STATUS
;
1118 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
1119 c
->opcode
= AVC_OPCODE_VENDOR
;
1121 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
1122 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
1123 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
1124 c
->operand
[3] = SFE_VENDOR_OPCODE_HOST2CA
;
1125 c
->operand
[4] = 0; /* slot */
1126 c
->operand
[5] = SFE_VENDOR_TAG_CA_ENTER_MENU
;
1127 c
->operand
[6] = 0; /* more/last */
1128 c
->operand
[7] = 0; /* length */
1132 if (avc_write(fdtv
, c
, r
) < 0)
1138 int avc_ca_get_mmi(struct firedtv
*fdtv
, char *mmi_object
, unsigned int *len
)
1140 char buffer
[sizeof(struct avc_command_frame
)];
1141 struct avc_command_frame
*c
= (void *)buffer
;
1142 struct avc_response_frame
*r
= (void *)buffer
;
1144 memset(c
, 0, sizeof(*c
));
1146 c
->ctype
= AVC_CTYPE_STATUS
;
1147 c
->subunit
= AVC_SUBUNIT_TYPE_TUNER
| fdtv
->subunit
;
1148 c
->opcode
= AVC_OPCODE_VENDOR
;
1150 c
->operand
[0] = SFE_VENDOR_DE_COMPANYID_0
;
1151 c
->operand
[1] = SFE_VENDOR_DE_COMPANYID_1
;
1152 c
->operand
[2] = SFE_VENDOR_DE_COMPANYID_2
;
1153 c
->operand
[3] = SFE_VENDOR_OPCODE_CA2HOST
;
1154 c
->operand
[4] = 0; /* slot */
1155 c
->operand
[5] = SFE_VENDOR_TAG_CA_MMI
;
1156 c
->operand
[6] = 0; /* more/last */
1157 c
->operand
[7] = 0; /* length */
1161 if (avc_write(fdtv
, c
, r
) < 0)
1164 /* FIXME: check response code and validate response data */
1166 *len
= get_ca_object_length(r
);
1167 memcpy(mmi_object
, &r
->operand
[get_ca_object_pos(r
)], *len
);
1172 #define CMP_OUTPUT_PLUG_CONTROL_REG_0 0xfffff0000904ULL
1174 static int cmp_read(struct firedtv
*fdtv
, void *buf
, u64 addr
, size_t len
)
1178 if (mutex_lock_interruptible(&fdtv
->avc_mutex
))
1181 ret
= fdtv
->backend
->read(fdtv
, addr
, buf
, len
);
1183 dev_err(fdtv
->device
, "CMP: read I/O error\n");
1185 mutex_unlock(&fdtv
->avc_mutex
);
1189 static int cmp_lock(struct firedtv
*fdtv
, void *data
, u64 addr
, __be32 arg
)
1193 if (mutex_lock_interruptible(&fdtv
->avc_mutex
))
1196 ret
= fdtv
->backend
->lock(fdtv
, addr
, data
, arg
);
1198 dev_err(fdtv
->device
, "CMP: lock I/O error\n");
1200 mutex_unlock(&fdtv
->avc_mutex
);
1204 static inline u32
get_opcr(__be32 opcr
, u32 mask
, u32 shift
)
1206 return (be32_to_cpu(opcr
) >> shift
) & mask
;
1209 static inline void set_opcr(__be32
*opcr
, u32 value
, u32 mask
, u32 shift
)
1211 *opcr
&= ~cpu_to_be32(mask
<< shift
);
1212 *opcr
|= cpu_to_be32((value
& mask
) << shift
);
1215 #define get_opcr_online(v) get_opcr((v), 0x1, 31)
1216 #define get_opcr_p2p_connections(v) get_opcr((v), 0x3f, 24)
1217 #define get_opcr_channel(v) get_opcr((v), 0x3f, 16)
1219 #define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
1220 #define set_opcr_channel(p, v) set_opcr((p), (v), 0x3f, 16)
1221 #define set_opcr_data_rate(p, v) set_opcr((p), (v), 0x3, 14)
1222 #define set_opcr_overhead_id(p, v) set_opcr((p), (v), 0xf, 10)
1224 int cmp_establish_pp_connection(struct firedtv
*fdtv
, int plug
, int channel
)
1226 __be32 old_opcr
, opcr
;
1227 u64 opcr_address
= CMP_OUTPUT_PLUG_CONTROL_REG_0
+ (plug
<< 2);
1231 ret
= cmp_read(fdtv
, &opcr
, opcr_address
, 4);
1236 if (!get_opcr_online(opcr
)) {
1237 dev_err(fdtv
->device
, "CMP: output offline\n");
1243 if (get_opcr_p2p_connections(opcr
)) {
1244 if (get_opcr_channel(opcr
) != channel
) {
1245 dev_err(fdtv
->device
, "CMP: cannot change channel\n");
1248 dev_info(fdtv
->device
, "CMP: overlaying connection\n");
1250 /* We don't allocate isochronous resources. */
1252 set_opcr_channel(&opcr
, channel
);
1253 set_opcr_data_rate(&opcr
, 2); /* S400 */
1255 /* FIXME: this is for the worst case - optimize */
1256 set_opcr_overhead_id(&opcr
, 0);
1259 * FIXME: allocate isochronous channel and bandwidth at IRM
1260 * fdtv->backend->alloc_resources(fdtv, channels_mask, bw);
1264 set_opcr_p2p_connections(&opcr
, get_opcr_p2p_connections(opcr
) + 1);
1266 ret
= cmp_lock(fdtv
, &opcr
, opcr_address
, old_opcr
);
1270 if (old_opcr
!= opcr
) {
1272 * FIXME: if old_opcr.P2P_Connections > 0,
1273 * deallocate isochronous channel and bandwidth at IRM
1275 * fdtv->backend->dealloc_resources(fdtv, channel, bw);
1278 if (++attempts
< 6) /* arbitrary limit */
1286 void cmp_break_pp_connection(struct firedtv
*fdtv
, int plug
, int channel
)
1288 __be32 old_opcr
, opcr
;
1289 u64 opcr_address
= CMP_OUTPUT_PLUG_CONTROL_REG_0
+ (plug
<< 2);
1292 if (cmp_read(fdtv
, &opcr
, opcr_address
, 4) < 0)
1296 if (!get_opcr_online(opcr
) || !get_opcr_p2p_connections(opcr
) ||
1297 get_opcr_channel(opcr
) != channel
) {
1298 dev_err(fdtv
->device
, "CMP: no connection to break\n");
1303 set_opcr_p2p_connections(&opcr
, get_opcr_p2p_connections(opcr
) - 1);
1305 if (cmp_lock(fdtv
, &opcr
, opcr_address
, old_opcr
) < 0)
1308 if (old_opcr
!= opcr
) {
1310 * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
1311 * owner, deallocate isochronous channel and bandwidth at IRM
1313 * fdtv->backend->dealloc_resources(fdtv, channel, bw);
1316 if (++attempts
< 6) /* arbitrary limit */