Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 1 | /* |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 2 | * FireDTV driver (formerly known as FireSAT) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 3 | * |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 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> |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 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 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 14 | #include <linux/bug.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 15 | #include <linux/crc32.h> |
| 16 | #include <linux/delay.h> |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 17 | #include <linux/device.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/moduleparam.h> |
| 20 | #include <linux/mutex.h> |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 21 | #include <linux/string.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 22 | #include <linux/wait.h> |
| 23 | #include <linux/workqueue.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 24 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 25 | #include <ieee1394_transactions.h> |
| 26 | #include <nodemgr.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 27 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 28 | #include "avc.h" |
| 29 | #include "firedtv.h" |
| 30 | #include "firedtv-rc.h" |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 31 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 32 | #define FCP_COMMAND_REGISTER 0xfffff0000b00ULL |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 33 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 34 | static int __avc_write(struct firedtv *fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 35 | const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 36 | { |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 37 | int err, retry; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 38 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 39 | if (RspFrm) |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 40 | fdtv->avc_reply_received = false; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 41 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 42 | for (retry = 0; retry < 6; retry++) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 43 | err = hpsb_node_write(fdtv->ud->ne, FCP_COMMAND_REGISTER, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 44 | (quadlet_t *)CmdFrm, CmdFrm->length); |
| 45 | if (err) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 46 | fdtv->avc_reply_received = true; |
| 47 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 48 | "FCP command write failed\n"); |
| 49 | return err; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 50 | } |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 51 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 52 | if (!RspFrm) |
| 53 | return 0; |
| 54 | |
| 55 | /* |
| 56 | * AV/C specs say that answers should be sent within 150 ms. |
| 57 | * Time out after 200 ms. |
| 58 | */ |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 59 | if (wait_event_timeout(fdtv->avc_wait, |
| 60 | fdtv->avc_reply_received, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 61 | HZ / 5) != 0) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 62 | memcpy(RspFrm, fdtv->respfrm, fdtv->resp_length); |
| 63 | RspFrm->length = fdtv->resp_length; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 64 | |
| 65 | return 0; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 66 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 67 | } |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 68 | dev_err(&fdtv->ud->device, "FCP response timed out\n"); |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 69 | return -ETIMEDOUT; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 70 | } |
| 71 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 72 | static int avc_write(struct firedtv *fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 73 | const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 74 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 75 | int ret; |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 76 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 77 | if (mutex_lock_interruptible(&fdtv->avc_mutex)) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 78 | return -EINTR; |
| 79 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 80 | ret = __avc_write(fdtv, CmdFrm, RspFrm); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 81 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 82 | mutex_unlock(&fdtv->avc_mutex); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 83 | return ret; |
| 84 | } |
| 85 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 86 | int avc_recv(struct firedtv *fdtv, u8 *data, size_t length) |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 87 | { |
| 88 | AVCRspFrm *RspFrm = (AVCRspFrm *)data; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 89 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 90 | if (length >= 8 && |
| 91 | RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && |
| 92 | RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && |
| 93 | RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && |
| 94 | RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { |
| 95 | if (RspFrm->resp == CHANGED) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 96 | fdtv_handle_rc(fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 97 | RspFrm->operand[4] << 8 | RspFrm->operand[5]); |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 98 | schedule_work(&fdtv->remote_ctrl_work); |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 99 | } else if (RspFrm->resp != INTERIM) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 100 | dev_info(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 101 | "remote control result = %d\n", RspFrm->resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 102 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 103 | return 0; |
| 104 | } |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 105 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 106 | if (fdtv->avc_reply_received) { |
| 107 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 108 | "received out-of-order AVC response, ignored\n"); |
| 109 | return -EIO; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 110 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 111 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 112 | memcpy(fdtv->respfrm, data, length); |
| 113 | fdtv->resp_length = length; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 114 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 115 | fdtv->avc_reply_received = true; |
| 116 | wake_up(&fdtv->avc_wait); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 117 | |
| 118 | return 0; |
| 119 | } |
| 120 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 121 | /* |
| 122 | * tuning command for setting the relative LNB frequency |
| 123 | * (not supported by the AVC standard) |
| 124 | */ |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 125 | static void avc_tuner_tuneqpsk(struct firedtv *fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 126 | struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) |
| 127 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 128 | CmdFrm->opcode = VENDOR; |
| 129 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 130 | CmdFrm->operand[0] = SFE_VENDOR_DE_COMPANYID_0; |
| 131 | CmdFrm->operand[1] = SFE_VENDOR_DE_COMPANYID_1; |
| 132 | CmdFrm->operand[2] = SFE_VENDOR_DE_COMPANYID_2; |
| 133 | CmdFrm->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 134 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 135 | CmdFrm->operand[4] = (params->frequency >> 24) & 0xff; |
| 136 | CmdFrm->operand[5] = (params->frequency >> 16) & 0xff; |
| 137 | CmdFrm->operand[6] = (params->frequency >> 8) & 0xff; |
| 138 | CmdFrm->operand[7] = params->frequency & 0xff; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 139 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 140 | CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff; |
| 141 | CmdFrm->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 142 | |
| 143 | switch(params->u.qpsk.fec_inner) { |
| 144 | case FEC_1_2: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 145 | CmdFrm->operand[10] = 0x1; break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 146 | case FEC_2_3: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 147 | CmdFrm->operand[10] = 0x2; break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 148 | case FEC_3_4: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 149 | CmdFrm->operand[10] = 0x3; break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 150 | case FEC_5_6: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 151 | CmdFrm->operand[10] = 0x4; break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 152 | case FEC_7_8: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 153 | CmdFrm->operand[10] = 0x5; break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 154 | case FEC_4_5: |
| 155 | case FEC_8_9: |
| 156 | case FEC_AUTO: |
| 157 | default: |
| 158 | CmdFrm->operand[10] = 0x0; |
| 159 | } |
| 160 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 161 | if (fdtv->voltage == 0xff) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 162 | CmdFrm->operand[11] = 0xff; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 163 | else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */ |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 164 | CmdFrm->operand[11] = 0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 165 | else |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 166 | CmdFrm->operand[11] = 1; |
| 167 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 168 | if (fdtv->tone == 0xff) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 169 | CmdFrm->operand[12] = 0xff; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 170 | else if (fdtv->tone == SEC_TONE_ON) /* band */ |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 171 | CmdFrm->operand[12] = 1; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 172 | else |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 173 | CmdFrm->operand[12] = 0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 174 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 175 | if (fdtv->type == FIREDTV_DVB_S2) { |
Ben Backx | 2c22861 | 2008-08-09 14:35:55 +0200 | [diff] [blame] | 176 | CmdFrm->operand[13] = 0x1; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 177 | CmdFrm->operand[14] = 0xff; |
| 178 | CmdFrm->operand[15] = 0xff; |
| 179 | CmdFrm->length = 20; |
| 180 | } else { |
| 181 | CmdFrm->length = 16; |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params, |
| 186 | AVCCmdFrm *CmdFrm) |
| 187 | { |
| 188 | M_VALID_FLAGS flags; |
| 189 | |
| 190 | flags.Bits.Modulation = params->u.qam.modulation != QAM_AUTO; |
| 191 | flags.Bits.FEC_inner = params->u.qam.fec_inner != FEC_AUTO; |
| 192 | flags.Bits.FEC_outer = 0; |
| 193 | flags.Bits.Symbol_Rate = 1; |
| 194 | flags.Bits.Frequency = 1; |
| 195 | flags.Bits.Orbital_Pos = 0; |
| 196 | flags.Bits.Polarisation = 0; |
| 197 | flags.Bits.reserved_fields = 0; |
| 198 | flags.Bits.reserved1 = 0; |
| 199 | flags.Bits.Network_ID = 0; |
| 200 | |
| 201 | CmdFrm->opcode = DSD; |
| 202 | |
| 203 | CmdFrm->operand[0] = 0; /* source plug */ |
| 204 | CmdFrm->operand[1] = 0xd2; /* subfunction replace */ |
| 205 | CmdFrm->operand[2] = 0x20; /* system id = DVB */ |
| 206 | CmdFrm->operand[3] = 0x00; /* antenna number */ |
| 207 | /* system_specific_multiplex selection_length */ |
| 208 | CmdFrm->operand[4] = 0x11; |
| 209 | CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ |
| 210 | CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ |
| 211 | CmdFrm->operand[7] = 0x00; |
| 212 | CmdFrm->operand[8] = 0x00; |
| 213 | CmdFrm->operand[9] = 0x00; |
| 214 | CmdFrm->operand[10] = 0x00; |
| 215 | |
| 216 | CmdFrm->operand[11] = |
| 217 | (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6); |
| 218 | CmdFrm->operand[12] = |
| 219 | ((params->frequency / 4000) >> 8) & 0xff; |
| 220 | CmdFrm->operand[13] = (params->frequency / 4000) & 0xff; |
| 221 | CmdFrm->operand[14] = |
| 222 | ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff; |
| 223 | CmdFrm->operand[15] = |
| 224 | ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff; |
| 225 | CmdFrm->operand[16] = |
| 226 | ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0; |
| 227 | CmdFrm->operand[17] = 0x00; |
| 228 | |
| 229 | switch (params->u.qpsk.fec_inner) { |
| 230 | case FEC_1_2: |
| 231 | CmdFrm->operand[18] = 0x1; break; |
| 232 | case FEC_2_3: |
| 233 | CmdFrm->operand[18] = 0x2; break; |
| 234 | case FEC_3_4: |
| 235 | CmdFrm->operand[18] = 0x3; break; |
| 236 | case FEC_5_6: |
| 237 | CmdFrm->operand[18] = 0x4; break; |
| 238 | case FEC_7_8: |
| 239 | CmdFrm->operand[18] = 0x5; break; |
| 240 | case FEC_8_9: |
| 241 | CmdFrm->operand[18] = 0x6; break; |
| 242 | case FEC_4_5: |
| 243 | CmdFrm->operand[18] = 0x8; break; |
| 244 | case FEC_AUTO: |
| 245 | default: |
| 246 | CmdFrm->operand[18] = 0x0; |
| 247 | } |
| 248 | switch (params->u.qam.modulation) { |
| 249 | case QAM_16: |
| 250 | CmdFrm->operand[19] = 0x08; break; |
| 251 | case QAM_32: |
| 252 | CmdFrm->operand[19] = 0x10; break; |
| 253 | case QAM_64: |
| 254 | CmdFrm->operand[19] = 0x18; break; |
| 255 | case QAM_128: |
| 256 | CmdFrm->operand[19] = 0x20; break; |
| 257 | case QAM_256: |
| 258 | CmdFrm->operand[19] = 0x28; break; |
| 259 | case QAM_AUTO: |
| 260 | default: |
| 261 | CmdFrm->operand[19] = 0x00; |
| 262 | } |
| 263 | CmdFrm->operand[20] = 0x00; |
| 264 | CmdFrm->operand[21] = 0x00; |
| 265 | /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ |
| 266 | CmdFrm->operand[22] = 0x00; |
| 267 | |
| 268 | CmdFrm->length = 28; |
| 269 | } |
| 270 | |
| 271 | static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params, |
| 272 | AVCCmdFrm *CmdFrm) |
| 273 | { |
| 274 | M_VALID_FLAGS flags; |
| 275 | |
| 276 | flags.Bits_T.GuardInterval = |
| 277 | params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO; |
| 278 | flags.Bits_T.CodeRateLPStream = |
| 279 | params->u.ofdm.code_rate_LP != FEC_AUTO; |
| 280 | flags.Bits_T.CodeRateHPStream = |
| 281 | params->u.ofdm.code_rate_HP != FEC_AUTO; |
| 282 | flags.Bits_T.HierarchyInfo = |
| 283 | params->u.ofdm.hierarchy_information != HIERARCHY_AUTO; |
| 284 | flags.Bits_T.Constellation = |
| 285 | params->u.ofdm.constellation != QAM_AUTO; |
| 286 | flags.Bits_T.Bandwidth = |
| 287 | params->u.ofdm.bandwidth != BANDWIDTH_AUTO; |
| 288 | flags.Bits_T.CenterFrequency = 1; |
| 289 | flags.Bits_T.reserved1 = 0; |
| 290 | flags.Bits_T.reserved2 = 0; |
| 291 | flags.Bits_T.OtherFrequencyFlag = 0; |
| 292 | flags.Bits_T.TransmissionMode = |
| 293 | params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO; |
| 294 | flags.Bits_T.NetworkId = 0; |
| 295 | |
| 296 | CmdFrm->opcode = DSD; |
| 297 | |
| 298 | CmdFrm->operand[0] = 0; /* source plug */ |
| 299 | CmdFrm->operand[1] = 0xd2; /* subfunction replace */ |
| 300 | CmdFrm->operand[2] = 0x20; /* system id = DVB */ |
| 301 | CmdFrm->operand[3] = 0x00; /* antenna number */ |
| 302 | /* system_specific_multiplex selection_length */ |
| 303 | CmdFrm->operand[4] = 0x0c; |
| 304 | CmdFrm->operand[5] = flags.Valid_Word.ByteHi; /* valid_flags [0] */ |
| 305 | CmdFrm->operand[6] = flags.Valid_Word.ByteLo; /* valid_flags [1] */ |
| 306 | CmdFrm->operand[7] = 0x0; |
| 307 | CmdFrm->operand[8] = (params->frequency / 10) >> 24; |
| 308 | CmdFrm->operand[9] = ((params->frequency / 10) >> 16) & 0xff; |
| 309 | CmdFrm->operand[10] = ((params->frequency / 10) >> 8) & 0xff; |
| 310 | CmdFrm->operand[11] = (params->frequency / 10) & 0xff; |
| 311 | |
| 312 | switch (params->u.ofdm.bandwidth) { |
| 313 | case BANDWIDTH_7_MHZ: |
| 314 | CmdFrm->operand[12] = 0x20; break; |
| 315 | case BANDWIDTH_8_MHZ: |
| 316 | case BANDWIDTH_6_MHZ: /* not defined by AVC spec */ |
| 317 | case BANDWIDTH_AUTO: |
| 318 | default: |
| 319 | CmdFrm->operand[12] = 0x00; |
| 320 | } |
| 321 | switch (params->u.ofdm.constellation) { |
| 322 | case QAM_16: |
| 323 | CmdFrm->operand[13] = 1 << 6; break; |
| 324 | case QAM_64: |
| 325 | CmdFrm->operand[13] = 2 << 6; break; |
| 326 | case QPSK: |
| 327 | default: |
| 328 | CmdFrm->operand[13] = 0x00; |
| 329 | } |
| 330 | switch (params->u.ofdm.hierarchy_information) { |
| 331 | case HIERARCHY_1: |
| 332 | CmdFrm->operand[13] |= 1 << 3; break; |
| 333 | case HIERARCHY_2: |
| 334 | CmdFrm->operand[13] |= 2 << 3; break; |
| 335 | case HIERARCHY_4: |
| 336 | CmdFrm->operand[13] |= 3 << 3; break; |
| 337 | case HIERARCHY_AUTO: |
| 338 | case HIERARCHY_NONE: |
| 339 | default: |
| 340 | break; |
| 341 | } |
| 342 | switch (params->u.ofdm.code_rate_HP) { |
| 343 | case FEC_2_3: |
| 344 | CmdFrm->operand[13] |= 1; break; |
| 345 | case FEC_3_4: |
| 346 | CmdFrm->operand[13] |= 2; break; |
| 347 | case FEC_5_6: |
| 348 | CmdFrm->operand[13] |= 3; break; |
| 349 | case FEC_7_8: |
| 350 | CmdFrm->operand[13] |= 4; break; |
| 351 | case FEC_1_2: |
| 352 | default: |
| 353 | break; |
| 354 | } |
| 355 | switch (params->u.ofdm.code_rate_LP) { |
| 356 | case FEC_2_3: |
| 357 | CmdFrm->operand[14] = 1 << 5; break; |
| 358 | case FEC_3_4: |
| 359 | CmdFrm->operand[14] = 2 << 5; break; |
| 360 | case FEC_5_6: |
| 361 | CmdFrm->operand[14] = 3 << 5; break; |
| 362 | case FEC_7_8: |
| 363 | CmdFrm->operand[14] = 4 << 5; break; |
| 364 | case FEC_1_2: |
| 365 | default: |
| 366 | CmdFrm->operand[14] = 0x00; break; |
| 367 | } |
| 368 | switch (params->u.ofdm.guard_interval) { |
| 369 | case GUARD_INTERVAL_1_16: |
| 370 | CmdFrm->operand[14] |= 1 << 3; break; |
| 371 | case GUARD_INTERVAL_1_8: |
| 372 | CmdFrm->operand[14] |= 2 << 3; break; |
| 373 | case GUARD_INTERVAL_1_4: |
| 374 | CmdFrm->operand[14] |= 3 << 3; break; |
| 375 | case GUARD_INTERVAL_1_32: |
| 376 | case GUARD_INTERVAL_AUTO: |
| 377 | default: |
| 378 | break; |
| 379 | } |
| 380 | switch (params->u.ofdm.transmission_mode) { |
| 381 | case TRANSMISSION_MODE_8K: |
| 382 | CmdFrm->operand[14] |= 1 << 1; break; |
| 383 | case TRANSMISSION_MODE_2K: |
| 384 | case TRANSMISSION_MODE_AUTO: |
| 385 | default: |
| 386 | break; |
Ben Backx | 2c22861 | 2008-08-09 14:35:55 +0200 | [diff] [blame] | 387 | } |
| 388 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 389 | CmdFrm->operand[15] = 0x00; /* network_ID[0] */ |
| 390 | CmdFrm->operand[16] = 0x00; /* network_ID[1] */ |
| 391 | /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */ |
| 392 | CmdFrm->operand[17] = 0x00; |
| 393 | |
| 394 | CmdFrm->length = 24; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 395 | } |
| 396 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 397 | int avc_tuner_dsd(struct firedtv *fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 398 | struct dvb_frontend_parameters *params) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 399 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 400 | AVCCmdFrm CmdFrm; |
| 401 | AVCRspFrm RspFrm; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 402 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 403 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 404 | |
| 405 | CmdFrm.cts = AVC; |
| 406 | CmdFrm.ctype = CONTROL; |
| 407 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 408 | CmdFrm.suid = fdtv->subunit; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 409 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 410 | switch (fdtv->type) { |
| 411 | case FIREDTV_DVB_S: |
| 412 | case FIREDTV_DVB_S2: |
| 413 | avc_tuner_tuneqpsk(fdtv, params, &CmdFrm); break; |
| 414 | case FIREDTV_DVB_C: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 415 | avc_tuner_dsd_dvb_c(params, &CmdFrm); break; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 416 | case FIREDTV_DVB_T: |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 417 | avc_tuner_dsd_dvb_t(params, &CmdFrm); break; |
| 418 | default: |
| 419 | BUG(); |
| 420 | } |
| 421 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 422 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 423 | return -EIO; |
| 424 | |
| 425 | msleep(500); |
| 426 | #if 0 |
| 427 | /* FIXME: */ |
| 428 | /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */ |
| 429 | if(status) |
| 430 | *status=RspFrm.operand[2]; |
| 431 | #endif |
| 432 | return 0; |
| 433 | } |
| 434 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 435 | int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 436 | { |
| 437 | AVCCmdFrm CmdFrm; |
| 438 | AVCRspFrm RspFrm; |
| 439 | int pos, k; |
| 440 | |
| 441 | if (pidc > 16 && pidc != 0xff) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 442 | return -EINVAL; |
| 443 | |
| 444 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 445 | |
| 446 | CmdFrm.cts = AVC; |
| 447 | CmdFrm.ctype = CONTROL; |
| 448 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 449 | CmdFrm.suid = fdtv->subunit; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 450 | CmdFrm.opcode = DSD; |
| 451 | |
| 452 | CmdFrm.operand[0] = 0; // source plug |
| 453 | CmdFrm.operand[1] = 0xD2; // subfunction replace |
| 454 | CmdFrm.operand[2] = 0x20; // system id = DVB |
| 455 | CmdFrm.operand[3] = 0x00; // antenna number |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 456 | CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length |
| 457 | CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 458 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 459 | pos = 6; |
| 460 | if (pidc != 0xff) |
| 461 | for (k = 0; k < pidc; k++) { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 462 | CmdFrm.operand[pos++] = 0x13; // flowfunction relay |
| 463 | CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID |
| 464 | CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; |
| 465 | CmdFrm.operand[pos++] = pid[k] & 0xFF; |
| 466 | CmdFrm.operand[pos++] = 0x00; // tableID |
| 467 | CmdFrm.operand[pos++] = 0x00; // filter_length |
| 468 | } |
| 469 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 470 | CmdFrm.length = ALIGN(3 + pos, 4); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 471 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 472 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 473 | return -EIO; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 474 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 475 | msleep(50); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 476 | return 0; |
| 477 | } |
| 478 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 479 | int avc_tuner_get_ts(struct firedtv *fdtv) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 480 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 481 | AVCCmdFrm CmdFrm; |
| 482 | AVCRspFrm RspFrm; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 483 | |
| 484 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 485 | |
| 486 | CmdFrm.cts = AVC; |
| 487 | CmdFrm.ctype = CONTROL; |
| 488 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 489 | CmdFrm.suid = fdtv->subunit; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 490 | CmdFrm.opcode = DSIT; |
| 491 | |
| 492 | CmdFrm.operand[0] = 0; // source plug |
| 493 | CmdFrm.operand[1] = 0xD2; // subfunction replace |
| 494 | CmdFrm.operand[2] = 0xFF; //status |
| 495 | CmdFrm.operand[3] = 0x20; // system id = DVB |
| 496 | CmdFrm.operand[4] = 0x00; // antenna number |
| 497 | CmdFrm.operand[5] = 0x0; // system_specific_search_flags |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 498 | CmdFrm.operand[6] = (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 499 | CmdFrm.operand[7] = 0x00; // valid_flags [0] |
| 500 | CmdFrm.operand[8] = 0x00; // valid_flags [1] |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 501 | CmdFrm.operand[7 + (fdtv->type == FIREDTV_DVB_T)?0x0c:0x11] = 0x00; // nr_of_dsit_sel_specs (always 0) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 502 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 503 | CmdFrm.length = (fdtv->type == FIREDTV_DVB_T)?24:28; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 504 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 505 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 506 | return -EIO; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 507 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 508 | msleep(250); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 509 | return 0; |
| 510 | } |
| 511 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 512 | int avc_identify_subunit(struct firedtv *fdtv) |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 513 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 514 | AVCCmdFrm CmdFrm; |
| 515 | AVCRspFrm RspFrm; |
| 516 | |
| 517 | memset(&CmdFrm,0,sizeof(AVCCmdFrm)); |
| 518 | |
| 519 | CmdFrm.cts = AVC; |
| 520 | CmdFrm.ctype = CONTROL; |
| 521 | CmdFrm.sutyp = 0x5; // tuner |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 522 | CmdFrm.suid = fdtv->subunit; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 523 | CmdFrm.opcode = READ_DESCRIPTOR; |
| 524 | |
| 525 | CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; |
| 526 | CmdFrm.operand[1]=0xff; |
| 527 | CmdFrm.operand[2]=0x00; |
| 528 | CmdFrm.operand[3]=0x00; // length highbyte |
| 529 | CmdFrm.operand[4]=0x08; // length lowbyte |
| 530 | CmdFrm.operand[5]=0x00; // offset highbyte |
| 531 | CmdFrm.operand[6]=0x0d; // offset lowbyte |
| 532 | |
| 533 | CmdFrm.length=12; |
| 534 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 535 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 536 | return -EIO; |
| 537 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 538 | if ((RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) || |
| 539 | (RspFrm.operand[3] << 8) + RspFrm.operand[4] != 8) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 540 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 541 | "cannot read subunit identifier\n"); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 542 | return -EINVAL; |
| 543 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 544 | return 0; |
| 545 | } |
| 546 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 547 | int avc_tuner_status(struct firedtv *fdtv, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 548 | ANTENNA_INPUT_INFO *antenna_input_info) |
| 549 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 550 | AVCCmdFrm CmdFrm; |
| 551 | AVCRspFrm RspFrm; |
| 552 | int length; |
| 553 | |
| 554 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 555 | |
| 556 | CmdFrm.cts=AVC; |
| 557 | CmdFrm.ctype=CONTROL; |
| 558 | CmdFrm.sutyp=0x05; // tuner |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 559 | CmdFrm.suid=fdtv->subunit; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 560 | CmdFrm.opcode=READ_DESCRIPTOR; |
| 561 | |
| 562 | CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 563 | CmdFrm.operand[1]=0xff; //read_result_status |
| 564 | CmdFrm.operand[2]=0x00; // reserver |
| 565 | CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; |
| 566 | CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 567 | CmdFrm.operand[5]=0x00; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 568 | CmdFrm.operand[6]=0x00; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 569 | CmdFrm.length=12; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 570 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 571 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 572 | return -EIO; |
| 573 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 574 | if (RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 575 | dev_err(&fdtv->ud->device, "cannot read tuner status\n"); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 576 | return -EINVAL; |
| 577 | } |
| 578 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 579 | length = RspFrm.operand[9]; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 580 | if (RspFrm.operand[1] != 0x10 || length != sizeof(ANTENNA_INPUT_INFO)) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 581 | dev_err(&fdtv->ud->device, "got invalid tuner status\n"); |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 582 | return -EINVAL; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 583 | } |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 584 | |
| 585 | memcpy(antenna_input_info, &RspFrm.operand[10], length); |
| 586 | return 0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 587 | } |
| 588 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 589 | int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 590 | char conttone, char nrdiseq, |
| 591 | struct dvb_diseqc_master_cmd *diseqcmd) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 592 | { |
| 593 | AVCCmdFrm CmdFrm; |
| 594 | AVCRspFrm RspFrm; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 595 | int i, j, k; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 596 | |
| 597 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 598 | |
| 599 | CmdFrm.cts=AVC; |
| 600 | CmdFrm.ctype=CONTROL; |
| 601 | CmdFrm.sutyp=0x05; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 602 | CmdFrm.suid=fdtv->subunit; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 603 | CmdFrm.opcode=VENDOR; |
| 604 | |
| 605 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 606 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 607 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 608 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; |
| 609 | |
| 610 | CmdFrm.operand[4]=voltage; |
| 611 | CmdFrm.operand[5]=nrdiseq; |
| 612 | |
| 613 | i=6; |
| 614 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 615 | for (j = 0; j < nrdiseq; j++) { |
| 616 | CmdFrm.operand[i++] = diseqcmd[j].msg_len; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 617 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 618 | for (k = 0; k < diseqcmd[j].msg_len; k++) |
| 619 | CmdFrm.operand[i++] = diseqcmd[j].msg[k]; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 620 | } |
| 621 | |
| 622 | CmdFrm.operand[i++]=burst; |
| 623 | CmdFrm.operand[i++]=conttone; |
| 624 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 625 | CmdFrm.length = ALIGN(3 + i, 4); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 626 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 627 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 628 | return -EIO; |
| 629 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 630 | if (RspFrm.resp != ACCEPTED) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 631 | dev_err(&fdtv->ud->device, "LNB control failed\n"); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 632 | return -EINVAL; |
| 633 | } |
| 634 | |
| 635 | return 0; |
| 636 | } |
| 637 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 638 | int avc_register_remote_control(struct firedtv *fdtv) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 639 | { |
| 640 | AVCCmdFrm CmdFrm; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 641 | |
| 642 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 643 | |
| 644 | CmdFrm.cts = AVC; |
| 645 | CmdFrm.ctype = NOTIFY; |
| 646 | CmdFrm.sutyp = 0x1f; |
| 647 | CmdFrm.suid = 0x7; |
| 648 | CmdFrm.opcode = VENDOR; |
| 649 | |
| 650 | CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0; |
| 651 | CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1; |
| 652 | CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2; |
| 653 | CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; |
| 654 | |
| 655 | CmdFrm.length = 8; |
| 656 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 657 | return avc_write(fdtv, &CmdFrm, NULL); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 658 | } |
| 659 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 660 | void avc_remote_ctrl_work(struct work_struct *work) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 661 | { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 662 | struct firedtv *fdtv = |
| 663 | container_of(work, struct firedtv, remote_ctrl_work); |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame] | 664 | |
| 665 | /* Should it be rescheduled in failure cases? */ |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 666 | avc_register_remote_control(fdtv); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 667 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 668 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 669 | #if 0 /* FIXME: unused */ |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 670 | int avc_tuner_host2ca(struct firedtv *fdtv) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 671 | { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 672 | AVCCmdFrm CmdFrm; |
| 673 | AVCRspFrm RspFrm; |
| 674 | |
| 675 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 676 | CmdFrm.cts = AVC; |
| 677 | CmdFrm.ctype = CONTROL; |
| 678 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 679 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 680 | CmdFrm.opcode = VENDOR; |
| 681 | |
| 682 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 683 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 684 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 685 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 686 | CmdFrm.operand[4] = 0; // slot |
| 687 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 688 | CmdFrm.operand[6] = 0; // more/last |
| 689 | CmdFrm.operand[7] = 0; // length |
| 690 | CmdFrm.length = 12; |
| 691 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 692 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 693 | return -EIO; |
| 694 | |
| 695 | return 0; |
| 696 | } |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 697 | #endif |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 698 | |
| 699 | static int get_ca_object_pos(AVCRspFrm *RspFrm) |
| 700 | { |
| 701 | int length = 1; |
| 702 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 703 | /* Check length of length field */ |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 704 | if (RspFrm->operand[7] & 0x80) |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 705 | length = (RspFrm->operand[7] & 0x7f) + 1; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 706 | return length + 7; |
| 707 | } |
| 708 | |
| 709 | static int get_ca_object_length(AVCRspFrm *RspFrm) |
| 710 | { |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 711 | #if 0 /* FIXME: unused */ |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 712 | int size = 0; |
| 713 | int i; |
| 714 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 715 | if (RspFrm->operand[7] & 0x80) |
| 716 | for (i = 0; i < (RspFrm->operand[7] & 0x7f); i++) { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 717 | size <<= 8; |
| 718 | size += RspFrm->operand[8 + i]; |
| 719 | } |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 720 | #endif |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 721 | return RspFrm->operand[7]; |
| 722 | } |
| 723 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 724 | int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 725 | { |
| 726 | AVCCmdFrm CmdFrm; |
| 727 | AVCRspFrm RspFrm; |
| 728 | int pos; |
| 729 | |
| 730 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 731 | CmdFrm.cts = AVC; |
| 732 | CmdFrm.ctype = STATUS; |
| 733 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 734 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 735 | CmdFrm.opcode = VENDOR; |
| 736 | |
| 737 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 738 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 739 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 740 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 741 | CmdFrm.operand[4] = 0; // slot |
| 742 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 743 | CmdFrm.length = 12; |
| 744 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 745 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 746 | return -EIO; |
| 747 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 748 | /* FIXME: check response code and validate response data */ |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 749 | |
| 750 | pos = get_ca_object_pos(&RspFrm); |
| 751 | app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; |
| 752 | app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; |
| 753 | app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; |
| 754 | app_info[3] = 6 + RspFrm.operand[pos + 4]; |
| 755 | app_info[4] = 0x01; |
| 756 | memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 757 | *len = app_info[3] + 4; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 758 | |
| 759 | return 0; |
| 760 | } |
| 761 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 762 | int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 763 | { |
| 764 | AVCCmdFrm CmdFrm; |
| 765 | AVCRspFrm RspFrm; |
Henrik Kurelid | 096edfb | 2008-12-04 22:40:52 +0100 | [diff] [blame] | 766 | int pos; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 767 | |
| 768 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 769 | CmdFrm.cts = AVC; |
| 770 | CmdFrm.ctype = STATUS; |
| 771 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 772 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 773 | CmdFrm.opcode = VENDOR; |
| 774 | |
| 775 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 776 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 777 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 778 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 779 | CmdFrm.operand[4] = 0; // slot |
| 780 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 781 | CmdFrm.length = 12; |
| 782 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 783 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 784 | return -EIO; |
| 785 | |
Henrik Kurelid | 096edfb | 2008-12-04 22:40:52 +0100 | [diff] [blame] | 786 | pos = get_ca_object_pos(&RspFrm); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 787 | app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; |
| 788 | app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; |
| 789 | app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; |
| 790 | app_info[3] = 2; |
Henrik Kurelid | 096edfb | 2008-12-04 22:40:52 +0100 | [diff] [blame] | 791 | app_info[4] = RspFrm.operand[pos + 0]; |
| 792 | app_info[5] = RspFrm.operand[pos + 1]; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 793 | *len = app_info[3] + 4; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 794 | |
| 795 | return 0; |
| 796 | } |
| 797 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 798 | int avc_ca_reset(struct firedtv *fdtv) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 799 | { |
| 800 | AVCCmdFrm CmdFrm; |
| 801 | AVCRspFrm RspFrm; |
| 802 | |
| 803 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 804 | CmdFrm.cts = AVC; |
| 805 | CmdFrm.ctype = CONTROL; |
| 806 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 807 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 808 | CmdFrm.opcode = VENDOR; |
| 809 | |
| 810 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 811 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 812 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 813 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 814 | CmdFrm.operand[4] = 0; // slot |
| 815 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag |
| 816 | CmdFrm.operand[6] = 0; // more/last |
| 817 | CmdFrm.operand[7] = 1; // length |
| 818 | CmdFrm.operand[8] = 0; // force hardware reset |
| 819 | CmdFrm.length = 12; |
| 820 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 821 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 822 | return -EIO; |
| 823 | |
| 824 | return 0; |
| 825 | } |
| 826 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 827 | int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 828 | { |
| 829 | AVCCmdFrm CmdFrm; |
| 830 | AVCRspFrm RspFrm; |
| 831 | int list_management; |
| 832 | int program_info_length; |
| 833 | int pmt_cmd_id; |
| 834 | int read_pos; |
| 835 | int write_pos; |
| 836 | int es_info_length; |
| 837 | int crc32_csum; |
| 838 | |
| 839 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 840 | CmdFrm.cts = AVC; |
| 841 | CmdFrm.ctype = CONTROL; |
| 842 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 843 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 844 | CmdFrm.opcode = VENDOR; |
| 845 | |
| 846 | if (msg[0] != LIST_MANAGEMENT_ONLY) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 847 | dev_info(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 848 | "forcing list_management to ONLY\n"); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 849 | msg[0] = LIST_MANAGEMENT_ONLY; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 850 | } |
| 851 | // We take the cmd_id from the programme level only! |
| 852 | list_management = msg[0]; |
| 853 | program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; |
| 854 | if (program_info_length > 0) |
| 855 | program_info_length--; // Remove pmt_cmd_id |
| 856 | pmt_cmd_id = msg[6]; |
| 857 | |
| 858 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 859 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 860 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 861 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 862 | CmdFrm.operand[4] = 0; // slot |
| 863 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag |
| 864 | CmdFrm.operand[6] = 0; // more/last |
| 865 | //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length |
| 866 | CmdFrm.operand[8] = list_management; |
| 867 | CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble |
| 868 | |
| 869 | // TS program map table |
| 870 | |
| 871 | // Table id=2 |
| 872 | CmdFrm.operand[10] = 0x02; |
| 873 | // Section syntax + length |
| 874 | CmdFrm.operand[11] = 0x80; |
| 875 | //CmdFrm.operand[12] = XXXprogram_info_length + 12; |
| 876 | // Program number |
| 877 | CmdFrm.operand[13] = msg[1]; |
| 878 | CmdFrm.operand[14] = msg[2]; |
| 879 | // Version number=0 + current/next=1 |
| 880 | CmdFrm.operand[15] = 0x01; |
| 881 | // Section number=0 |
| 882 | CmdFrm.operand[16] = 0x00; |
| 883 | // Last section number=0 |
| 884 | CmdFrm.operand[17] = 0x00; |
| 885 | // PCR_PID=1FFF |
| 886 | CmdFrm.operand[18] = 0x1F; |
| 887 | CmdFrm.operand[19] = 0xFF; |
| 888 | // Program info length |
| 889 | CmdFrm.operand[20] = (program_info_length >> 8); |
| 890 | CmdFrm.operand[21] = (program_info_length & 0xFF); |
| 891 | // CA descriptors at programme level |
| 892 | read_pos = 6; |
| 893 | write_pos = 22; |
| 894 | if (program_info_length > 0) { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 895 | pmt_cmd_id = msg[read_pos++]; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 896 | if (pmt_cmd_id != 1 && pmt_cmd_id != 4) |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 897 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 898 | "invalid pmt_cmd_id %d\n", pmt_cmd_id); |
| 899 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 900 | memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], |
| 901 | program_info_length); |
| 902 | read_pos += program_info_length; |
| 903 | write_pos += program_info_length; |
| 904 | } |
| 905 | while (read_pos < length) { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 906 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 907 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 908 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 909 | es_info_length = |
| 910 | ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; |
| 911 | read_pos += 2; |
| 912 | if (es_info_length > 0) |
| 913 | es_info_length--; // Remove pmt_cmd_id |
| 914 | CmdFrm.operand[write_pos++] = es_info_length >> 8; |
| 915 | CmdFrm.operand[write_pos++] = es_info_length & 0xFF; |
| 916 | if (es_info_length > 0) { |
| 917 | pmt_cmd_id = msg[read_pos++]; |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 918 | if (pmt_cmd_id != 1 && pmt_cmd_id != 4) |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 919 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 920 | "invalid pmt_cmd_id %d " |
| 921 | "at stream level\n", pmt_cmd_id); |
| 922 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 923 | memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], |
| 924 | es_info_length); |
| 925 | read_pos += es_info_length; |
| 926 | write_pos += es_info_length; |
| 927 | } |
| 928 | } |
| 929 | |
| 930 | // CRC |
| 931 | CmdFrm.operand[write_pos++] = 0x00; |
| 932 | CmdFrm.operand[write_pos++] = 0x00; |
| 933 | CmdFrm.operand[write_pos++] = 0x00; |
| 934 | CmdFrm.operand[write_pos++] = 0x00; |
| 935 | |
| 936 | CmdFrm.operand[7] = write_pos - 8; |
| 937 | CmdFrm.operand[12] = write_pos - 13; |
| 938 | |
| 939 | crc32_csum = crc32_be(0, &CmdFrm.operand[10], |
| 940 | CmdFrm.operand[12] - 1); |
| 941 | CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; |
| 942 | CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; |
| 943 | CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; |
| 944 | CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; |
| 945 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 946 | CmdFrm.length = ALIGN(3 + write_pos, 4); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 947 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 948 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 949 | return -EIO; |
| 950 | |
| 951 | if (RspFrm.resp != ACCEPTED) { |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 952 | dev_err(&fdtv->ud->device, |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 953 | "CA PMT failed with response 0x%x\n", RspFrm.resp); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 954 | return -EFAULT; |
| 955 | } |
| 956 | |
| 957 | return 0; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 958 | } |
| 959 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 960 | int avc_ca_get_time_date(struct firedtv *fdtv, int *interval) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 961 | { |
| 962 | AVCCmdFrm CmdFrm; |
| 963 | AVCRspFrm RspFrm; |
| 964 | |
| 965 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 966 | CmdFrm.cts = AVC; |
| 967 | CmdFrm.ctype = STATUS; |
| 968 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 969 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 970 | CmdFrm.opcode = VENDOR; |
| 971 | |
| 972 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 973 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 974 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 975 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 976 | CmdFrm.operand[4] = 0; // slot |
| 977 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag |
| 978 | CmdFrm.operand[6] = 0; // more/last |
| 979 | CmdFrm.operand[7] = 0; // length |
| 980 | CmdFrm.length = 12; |
| 981 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 982 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 983 | return -EIO; |
| 984 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 985 | /* FIXME: check response code and validate response data */ |
| 986 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 987 | *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; |
| 988 | |
| 989 | return 0; |
| 990 | } |
| 991 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 992 | int avc_ca_enter_menu(struct firedtv *fdtv) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 993 | { |
| 994 | AVCCmdFrm CmdFrm; |
| 995 | AVCRspFrm RspFrm; |
| 996 | |
| 997 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 998 | CmdFrm.cts = AVC; |
| 999 | CmdFrm.ctype = STATUS; |
| 1000 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 1001 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1002 | CmdFrm.opcode = VENDOR; |
| 1003 | |
| 1004 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1005 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1006 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1007 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 1008 | CmdFrm.operand[4] = 0; // slot |
| 1009 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; |
| 1010 | CmdFrm.operand[6] = 0; // more/last |
| 1011 | CmdFrm.operand[7] = 0; // length |
| 1012 | CmdFrm.length = 12; |
| 1013 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 1014 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1015 | return -EIO; |
| 1016 | |
| 1017 | return 0; |
| 1018 | } |
| 1019 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 1020 | int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1021 | { |
| 1022 | AVCCmdFrm CmdFrm; |
| 1023 | AVCRspFrm RspFrm; |
| 1024 | |
| 1025 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1026 | CmdFrm.cts = AVC; |
| 1027 | CmdFrm.ctype = STATUS; |
| 1028 | CmdFrm.sutyp = 0x5; |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 1029 | CmdFrm.suid = fdtv->subunit; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1030 | CmdFrm.opcode = VENDOR; |
| 1031 | |
| 1032 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1033 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1034 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1035 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 1036 | CmdFrm.operand[4] = 0; // slot |
| 1037 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; |
| 1038 | CmdFrm.operand[6] = 0; // more/last |
| 1039 | CmdFrm.operand[7] = 0; // length |
| 1040 | CmdFrm.length = 12; |
| 1041 | |
Rambaldi | a70f81c | 2009-01-17 14:47:34 +0100 | [diff] [blame^] | 1042 | if (avc_write(fdtv, &CmdFrm, &RspFrm) < 0) |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1043 | return -EIO; |
| 1044 | |
Stefan Richter | 8ae83cd | 2008-11-02 13:45:00 +0100 | [diff] [blame] | 1045 | /* FIXME: check response code and validate response data */ |
| 1046 | |
| 1047 | *len = get_ca_object_length(&RspFrm); |
| 1048 | memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *len); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1049 | |
| 1050 | return 0; |
| 1051 | } |