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 | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 14 | #include <linux/crc32.h> |
| 15 | #include <linux/delay.h> |
| 16 | #include <linux/kernel.h> |
| 17 | #include <linux/moduleparam.h> |
| 18 | #include <linux/mutex.h> |
| 19 | #include <linux/wait.h> |
| 20 | #include <linux/workqueue.h> |
| 21 | #include <asm/atomic.h> |
| 22 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 23 | #include <ieee1394_transactions.h> |
| 24 | #include <nodemgr.h> |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 25 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 26 | #include "avc_api.h" |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 27 | #include "firesat.h" |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 28 | #include "firesat-rc.h" |
| 29 | |
| 30 | #define RESPONSE_REGISTER 0xFFFFF0000D00ULL |
| 31 | #define COMMAND_REGISTER 0xFFFFF0000B00ULL |
| 32 | #define PCR_BASE_ADDRESS 0xFFFFF0000900ULL |
| 33 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 34 | static unsigned int avc_comm_debug = 0; |
| 35 | module_param(avc_comm_debug, int, 0644); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 36 | MODULE_PARM_DESC(avc_comm_debug, "debug logging level [0..2] of AV/C communication, default is 0 (no)"); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 37 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 38 | /* Frees an allocated packet */ |
| 39 | static void avc_free_packet(struct hpsb_packet *packet) |
| 40 | { |
| 41 | hpsb_free_tlabel(packet); |
| 42 | hpsb_free_packet(packet); |
| 43 | } |
| 44 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 45 | static const char* get_ctype_string(__u8 ctype) |
| 46 | { |
| 47 | switch(ctype) |
| 48 | { |
| 49 | case 0: |
| 50 | return "CONTROL"; |
| 51 | case 1: |
| 52 | return "STATUS"; |
| 53 | case 2: |
| 54 | return "SPECIFIC_INQUIRY"; |
| 55 | case 3: |
| 56 | return "NOTIFY"; |
| 57 | case 4: |
| 58 | return "GENERAL_INQUIRY"; |
| 59 | } |
| 60 | return "UNKNOWN"; |
| 61 | } |
| 62 | |
| 63 | static const char* get_resp_string(__u8 ctype) |
| 64 | { |
| 65 | switch(ctype) |
| 66 | { |
| 67 | case 8: |
| 68 | return "NOT_IMPLEMENTED"; |
| 69 | case 9: |
| 70 | return "ACCEPTED"; |
| 71 | case 10: |
| 72 | return "REJECTED"; |
| 73 | case 11: |
| 74 | return "IN_TRANSITION"; |
| 75 | case 12: |
| 76 | return "IMPLEMENTED_STABLE"; |
| 77 | case 13: |
| 78 | return "CHANGED"; |
| 79 | case 15: |
| 80 | return "INTERIM"; |
| 81 | } |
| 82 | return "UNKNOWN"; |
| 83 | } |
| 84 | |
| 85 | static const char* get_subunit_address(__u8 subunit_id, __u8 subunit_type) |
| 86 | { |
| 87 | if (subunit_id == 7 && subunit_type == 0x1F) |
| 88 | return "Unit"; |
| 89 | if (subunit_id == 0 && subunit_type == 0x05) |
| 90 | return "Tuner(0)"; |
| 91 | return "Unsupported"; |
| 92 | } |
| 93 | |
| 94 | static const char* get_opcode_string(__u8 opcode) |
| 95 | { |
| 96 | switch(opcode) |
| 97 | { |
| 98 | case 0x02: |
| 99 | return "PlugInfo"; |
| 100 | case 0x08: |
| 101 | return "OpenDescriptor"; |
| 102 | case 0x09: |
| 103 | return "ReadDescriptor"; |
| 104 | case 0x18: |
| 105 | return "OutputPlugSignalFormat"; |
| 106 | case 0x31: |
| 107 | return "SubunitInfo"; |
| 108 | case 0x30: |
| 109 | return "UnitInfo"; |
| 110 | case 0xB2: |
| 111 | return "Power"; |
| 112 | case 0xC8: |
| 113 | return "DirectSelectInformationType"; |
| 114 | case 0xCB: |
| 115 | return "DirectSelectData"; |
| 116 | case 0x00: |
| 117 | return "Vendor"; |
| 118 | |
| 119 | } |
| 120 | return "Unknown"; |
| 121 | } |
| 122 | |
| 123 | static void log_command_frame(const AVCCmdFrm *CmdFrm) |
| 124 | { |
| 125 | int k; |
| 126 | printk(KERN_INFO "AV/C Command Frame:\n"); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 127 | printk(KERN_INFO "CommandType=%s, Address=%s(0x%02X,0x%02X), " |
| 128 | "opcode=%s(0x%02X), length=%d\n", |
| 129 | get_ctype_string(CmdFrm->ctype), |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 130 | get_subunit_address(CmdFrm->suid, CmdFrm->sutyp), |
| 131 | CmdFrm->suid, CmdFrm->sutyp, get_opcode_string(CmdFrm->opcode), |
| 132 | CmdFrm->opcode, CmdFrm->length); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 133 | if (avc_comm_debug > 1) { |
| 134 | for(k = 0; k < CmdFrm->length - 3; k++) { |
| 135 | if (k % 5 != 0) |
| 136 | printk(", "); |
| 137 | else if (k != 0) |
| 138 | printk("\n"); |
| 139 | printk(KERN_INFO "operand[%d] = %02X", k, |
| 140 | CmdFrm->operand[k]); |
| 141 | } |
| 142 | printk(KERN_INFO "\n"); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 143 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | static void log_response_frame(const AVCRspFrm *RspFrm) |
| 147 | { |
| 148 | int k; |
| 149 | printk(KERN_INFO "AV/C Response Frame:\n"); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 150 | printk(KERN_INFO "Response=%s, Address=%s(0x%02X,0x%02X), " |
| 151 | "opcode=%s(0x%02X), length=%d\n", get_resp_string(RspFrm->resp), |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 152 | get_subunit_address(RspFrm->suid, RspFrm->sutyp), |
| 153 | RspFrm->suid, RspFrm->sutyp, get_opcode_string(RspFrm->opcode), |
| 154 | RspFrm->opcode, RspFrm->length); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 155 | if (avc_comm_debug > 1) { |
| 156 | for(k = 0; k < RspFrm->length - 3; k++) { |
| 157 | if (k % 5 != 0) |
| 158 | printk(KERN_INFO ", "); |
| 159 | else if (k != 0) |
| 160 | printk(KERN_INFO "\n"); |
| 161 | printk(KERN_INFO "operand[%d] = %02X", k, |
| 162 | RspFrm->operand[k]); |
| 163 | } |
| 164 | printk(KERN_INFO "\n"); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 165 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 166 | } |
| 167 | |
| 168 | static int __AVCWrite(struct firesat *firesat, const AVCCmdFrm *CmdFrm, |
| 169 | AVCRspFrm *RspFrm) { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 170 | struct hpsb_packet *packet; |
| 171 | struct node_entry *ne; |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 172 | int num_tries = 0; |
| 173 | int packet_ok = 0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 174 | |
| 175 | ne = firesat->nodeentry; |
| 176 | if(!ne) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 177 | printk(KERN_ERR "%s: lost node!\n",__func__); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 178 | return -EIO; |
| 179 | } |
| 180 | |
| 181 | /* need all input data */ |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 182 | if(!firesat || !ne || !CmdFrm) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 183 | printk(KERN_ERR "%s: missing input data!\n",__func__); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 184 | return -EINVAL; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 185 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 186 | |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 187 | if (avc_comm_debug > 0) { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 188 | log_command_frame(CmdFrm); |
| 189 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 190 | |
| 191 | if(RspFrm) |
| 192 | atomic_set(&firesat->avc_reply_received, 0); |
| 193 | |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 194 | while (packet_ok == 0 && num_tries < 6) { |
| 195 | num_tries++; |
| 196 | packet_ok = 1; |
| 197 | packet = hpsb_make_writepacket(ne->host, ne->nodeid, |
| 198 | COMMAND_REGISTER, |
| 199 | (quadlet_t*)CmdFrm, |
| 200 | CmdFrm->length); |
| 201 | hpsb_set_packet_complete_task(packet, |
| 202 | (void (*)(void*))avc_free_packet, |
| 203 | packet); |
| 204 | hpsb_node_fill_packet(ne, packet); |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 205 | |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 206 | if (hpsb_send_packet(packet) < 0) { |
| 207 | avc_free_packet(packet); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 208 | atomic_set(&firesat->avc_reply_received, 1); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 209 | printk(KERN_ERR "%s: send failed!\n",__func__); |
| 210 | return -EIO; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 211 | } |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 212 | |
| 213 | if(RspFrm) { |
| 214 | // AV/C specs say that answers should be send within |
| 215 | // 150 ms so let's time out after 200 ms |
| 216 | if (wait_event_timeout(firesat->avc_wait, |
| 217 | atomic_read(&firesat->avc_reply_received) == 1, |
| 218 | HZ / 5) == 0) { |
| 219 | packet_ok = 0; |
| 220 | } |
| 221 | else { |
| 222 | memcpy(RspFrm, firesat->respfrm, |
| 223 | firesat->resp_length); |
| 224 | RspFrm->length = firesat->resp_length; |
| 225 | if (avc_comm_debug > 0) { |
| 226 | log_response_frame(RspFrm); |
| 227 | } |
| 228 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 229 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 230 | } |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 231 | if (packet_ok == 0) { |
| 232 | printk(KERN_ERR "%s: AV/C response timed out 6 times.\n", |
| 233 | __func__); |
| 234 | return -ETIMEDOUT; |
| 235 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 236 | |
| 237 | return 0; |
| 238 | } |
| 239 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 240 | int AVCWrite(struct firesat*firesat, const AVCCmdFrm *CmdFrm, AVCRspFrm *RspFrm) |
| 241 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 242 | int ret; |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 243 | |
| 244 | if (mutex_lock_interruptible(&firesat->avc_mutex)) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 245 | return -EINTR; |
| 246 | |
| 247 | ret = __AVCWrite(firesat, CmdFrm, RspFrm); |
| 248 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 249 | mutex_unlock(&firesat->avc_mutex); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 250 | return ret; |
| 251 | } |
| 252 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 253 | int AVCRecv(struct firesat *firesat, u8 *data, size_t length) |
| 254 | { |
| 255 | AVCRspFrm *RspFrm = (AVCRspFrm *)data; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 256 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 257 | if (length >= 8 && |
| 258 | RspFrm->operand[0] == SFE_VENDOR_DE_COMPANYID_0 && |
| 259 | RspFrm->operand[1] == SFE_VENDOR_DE_COMPANYID_1 && |
| 260 | RspFrm->operand[2] == SFE_VENDOR_DE_COMPANYID_2 && |
| 261 | RspFrm->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) { |
| 262 | if (RspFrm->resp == CHANGED) { |
| 263 | firesat_handle_rc(RspFrm->operand[4] << 8 | |
| 264 | RspFrm->operand[5]); |
| 265 | schedule_work(&firesat->remote_ctrl_work); |
| 266 | } else if (RspFrm->resp != INTERIM) { |
| 267 | printk(KERN_INFO "firedtv: remote control result = " |
| 268 | "%d\n", RspFrm->resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 269 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 270 | return 0; |
| 271 | } |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 272 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 273 | if(atomic_read(&firesat->avc_reply_received) == 1) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 274 | printk(KERN_ERR "%s: received out-of-order AVC response, " |
| 275 | "ignored\n",__func__); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 276 | return -EINVAL; |
| 277 | } |
| 278 | // AVCRspFrm *resp=(AVCRspFrm *)data; |
| 279 | // int k; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 280 | |
| 281 | // printk(KERN_INFO "resp=0x%x\n",resp->resp); |
| 282 | // printk(KERN_INFO "cts=0x%x\n",resp->cts); |
| 283 | // printk(KERN_INFO "suid=0x%x\n",resp->suid); |
| 284 | // printk(KERN_INFO "sutyp=0x%x\n",resp->sutyp); |
| 285 | // printk(KERN_INFO "opcode=0x%x\n",resp->opcode); |
| 286 | // printk(KERN_INFO "length=%d\n",resp->length); |
| 287 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 288 | // for(k=0;k<2;k++) |
| 289 | // printk(KERN_INFO "operand[%d]=%02x\n",k,resp->operand[k]); |
| 290 | |
| 291 | memcpy(firesat->respfrm,data,length); |
| 292 | firesat->resp_length=length; |
| 293 | |
| 294 | atomic_set(&firesat->avc_reply_received, 1); |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 295 | wake_up(&firesat->avc_wait); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 296 | |
| 297 | return 0; |
| 298 | } |
| 299 | |
| 300 | // tuning command for setting the relative LNB frequency (not supported by the AVC standard) |
| 301 | static void AVCTuner_tuneQPSK(struct firesat *firesat, struct dvb_frontend_parameters *params, AVCCmdFrm *CmdFrm) { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 302 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 303 | memset(CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 304 | |
| 305 | CmdFrm->cts = AVC; |
| 306 | CmdFrm->ctype = CONTROL; |
| 307 | CmdFrm->sutyp = 0x5; |
| 308 | CmdFrm->suid = firesat->subunit; |
| 309 | CmdFrm->opcode = VENDOR; |
| 310 | |
| 311 | CmdFrm->operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 312 | CmdFrm->operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 313 | CmdFrm->operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 314 | CmdFrm->operand[3]=SFE_VENDOR_OPCODE_TUNE_QPSK; |
| 315 | |
| 316 | printk(KERN_INFO "%s: tuning to frequency %u\n",__func__,params->frequency); |
| 317 | |
| 318 | CmdFrm->operand[4] = (params->frequency >> 24) & 0xFF; |
| 319 | CmdFrm->operand[5] = (params->frequency >> 16) & 0xFF; |
| 320 | CmdFrm->operand[6] = (params->frequency >> 8) & 0xFF; |
| 321 | CmdFrm->operand[7] = params->frequency & 0xFF; |
| 322 | |
| 323 | printk(KERN_INFO "%s: symbol rate = %uBd\n",__func__,params->u.qpsk.symbol_rate); |
| 324 | |
| 325 | CmdFrm->operand[8] = ((params->u.qpsk.symbol_rate/1000) >> 8) & 0xFF; |
| 326 | CmdFrm->operand[9] = (params->u.qpsk.symbol_rate/1000) & 0xFF; |
| 327 | |
| 328 | switch(params->u.qpsk.fec_inner) { |
| 329 | case FEC_1_2: |
| 330 | CmdFrm->operand[10] = 0x1; |
| 331 | break; |
| 332 | case FEC_2_3: |
| 333 | CmdFrm->operand[10] = 0x2; |
| 334 | break; |
| 335 | case FEC_3_4: |
| 336 | CmdFrm->operand[10] = 0x3; |
| 337 | break; |
| 338 | case FEC_5_6: |
| 339 | CmdFrm->operand[10] = 0x4; |
| 340 | break; |
| 341 | case FEC_7_8: |
| 342 | CmdFrm->operand[10] = 0x5; |
| 343 | break; |
| 344 | case FEC_4_5: |
| 345 | case FEC_8_9: |
| 346 | case FEC_AUTO: |
| 347 | default: |
| 348 | CmdFrm->operand[10] = 0x0; |
| 349 | } |
| 350 | |
| 351 | if(firesat->voltage == 0xff) |
| 352 | CmdFrm->operand[11] = 0xff; |
| 353 | else |
| 354 | CmdFrm->operand[11] = (firesat->voltage==SEC_VOLTAGE_18)?0:1; // polarisation |
| 355 | if(firesat->tone == 0xff) |
| 356 | CmdFrm->operand[12] = 0xff; |
| 357 | else |
| 358 | CmdFrm->operand[12] = (firesat->tone==SEC_TONE_ON)?1:0; // band |
| 359 | |
Ben Backx | 2c22861 | 2008-08-09 14:35:55 +0200 | [diff] [blame] | 360 | if (firesat->type == FireSAT_DVB_S2) { |
| 361 | CmdFrm->operand[13] = 0x1; |
| 362 | CmdFrm->operand[14] = 0xFF; |
| 363 | CmdFrm->operand[15] = 0xFF; |
| 364 | } |
| 365 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 366 | CmdFrm->length = 16; |
| 367 | } |
| 368 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 369 | int AVCTuner_DSD(struct firesat *firesat, struct dvb_frontend_parameters *params, __u8 *status) { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 370 | AVCCmdFrm CmdFrm; |
| 371 | AVCRspFrm RspFrm; |
| 372 | M_VALID_FLAGS flags; |
| 373 | int k; |
| 374 | |
| 375 | // printk(KERN_INFO "%s\n", __func__); |
| 376 | |
Ben Backx | f1bbb43 | 2008-06-22 16:00:53 +0200 | [diff] [blame] | 377 | if (firesat->type == FireSAT_DVB_S || firesat->type == FireSAT_DVB_S2) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 378 | AVCTuner_tuneQPSK(firesat, params, &CmdFrm); |
| 379 | else { |
| 380 | if(firesat->type == FireSAT_DVB_T) { |
| 381 | flags.Bits_T.GuardInterval = (params->u.ofdm.guard_interval != GUARD_INTERVAL_AUTO); |
| 382 | flags.Bits_T.CodeRateLPStream = (params->u.ofdm.code_rate_LP != FEC_AUTO); |
| 383 | flags.Bits_T.CodeRateHPStream = (params->u.ofdm.code_rate_HP != FEC_AUTO); |
| 384 | flags.Bits_T.HierarchyInfo = (params->u.ofdm.hierarchy_information != HIERARCHY_AUTO); |
| 385 | flags.Bits_T.Constellation = (params->u.ofdm.constellation != QAM_AUTO); |
| 386 | flags.Bits_T.Bandwidth = (params->u.ofdm.bandwidth != BANDWIDTH_AUTO); |
| 387 | flags.Bits_T.CenterFrequency = 1; |
| 388 | flags.Bits_T.reserved1 = 0; |
| 389 | flags.Bits_T.reserved2 = 0; |
| 390 | flags.Bits_T.OtherFrequencyFlag = 0; |
| 391 | flags.Bits_T.TransmissionMode = (params->u.ofdm.transmission_mode != TRANSMISSION_MODE_AUTO); |
| 392 | flags.Bits_T.NetworkId = 0; |
| 393 | } else { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 394 | flags.Bits.Modulation = |
| 395 | (params->u.qam.modulation != QAM_AUTO); |
| 396 | flags.Bits.FEC_inner = |
| 397 | (params->u.qam.fec_inner != FEC_AUTO); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 398 | flags.Bits.FEC_outer = 0; |
| 399 | flags.Bits.Symbol_Rate = 1; |
| 400 | flags.Bits.Frequency = 1; |
| 401 | flags.Bits.Orbital_Pos = 0; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 402 | flags.Bits.Polarisation = 0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 403 | flags.Bits.reserved_fields = 0; |
| 404 | flags.Bits.reserved1 = 0; |
| 405 | flags.Bits.Network_ID = 0; |
| 406 | } |
| 407 | |
| 408 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 409 | |
| 410 | CmdFrm.cts = AVC; |
| 411 | CmdFrm.ctype = CONTROL; |
| 412 | CmdFrm.sutyp = 0x5; |
| 413 | CmdFrm.suid = firesat->subunit; |
| 414 | CmdFrm.opcode = DSD; |
| 415 | |
| 416 | CmdFrm.operand[0] = 0; // source plug |
| 417 | CmdFrm.operand[1] = 0xD2; // subfunction replace |
| 418 | CmdFrm.operand[2] = 0x20; // system id = DVB |
| 419 | CmdFrm.operand[3] = 0x00; // antenna number |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 420 | // system_specific_multiplex selection_length |
| 421 | CmdFrm.operand[4] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 422 | CmdFrm.operand[5] = flags.Valid_Word.ByteHi; // valid_flags [0] |
| 423 | CmdFrm.operand[6] = flags.Valid_Word.ByteLo; // valid_flags [1] |
| 424 | |
| 425 | if(firesat->type == FireSAT_DVB_T) { |
| 426 | CmdFrm.operand[7] = 0x0; |
| 427 | CmdFrm.operand[8] = (params->frequency/10) >> 24; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 428 | CmdFrm.operand[9] = |
| 429 | ((params->frequency/10) >> 16) & 0xFF; |
| 430 | CmdFrm.operand[10] = |
| 431 | ((params->frequency/10) >> 8) & 0xFF; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 432 | CmdFrm.operand[11] = (params->frequency/10) & 0xFF; |
| 433 | switch(params->u.ofdm.bandwidth) { |
| 434 | case BANDWIDTH_7_MHZ: |
| 435 | CmdFrm.operand[12] = 0x20; |
| 436 | break; |
| 437 | case BANDWIDTH_8_MHZ: |
| 438 | case BANDWIDTH_6_MHZ: // not defined by AVC spec |
| 439 | case BANDWIDTH_AUTO: |
| 440 | default: |
| 441 | CmdFrm.operand[12] = 0x00; |
| 442 | } |
| 443 | switch(params->u.ofdm.constellation) { |
| 444 | case QAM_16: |
| 445 | CmdFrm.operand[13] = 1 << 6; |
| 446 | break; |
| 447 | case QAM_64: |
| 448 | CmdFrm.operand[13] = 2 << 6; |
| 449 | break; |
| 450 | case QPSK: |
| 451 | default: |
| 452 | CmdFrm.operand[13] = 0x00; |
| 453 | } |
| 454 | switch(params->u.ofdm.hierarchy_information) { |
| 455 | case HIERARCHY_1: |
| 456 | CmdFrm.operand[13] |= 1 << 3; |
| 457 | break; |
| 458 | case HIERARCHY_2: |
| 459 | CmdFrm.operand[13] |= 2 << 3; |
| 460 | break; |
| 461 | case HIERARCHY_4: |
| 462 | CmdFrm.operand[13] |= 3 << 3; |
| 463 | break; |
| 464 | case HIERARCHY_AUTO: |
| 465 | case HIERARCHY_NONE: |
| 466 | default: |
| 467 | break; |
| 468 | } |
| 469 | switch(params->u.ofdm.code_rate_HP) { |
| 470 | case FEC_2_3: |
| 471 | CmdFrm.operand[13] |= 1; |
| 472 | break; |
| 473 | case FEC_3_4: |
| 474 | CmdFrm.operand[13] |= 2; |
| 475 | break; |
| 476 | case FEC_5_6: |
| 477 | CmdFrm.operand[13] |= 3; |
| 478 | break; |
| 479 | case FEC_7_8: |
| 480 | CmdFrm.operand[13] |= 4; |
| 481 | break; |
| 482 | case FEC_1_2: |
| 483 | default: |
| 484 | break; |
| 485 | } |
| 486 | switch(params->u.ofdm.code_rate_LP) { |
| 487 | case FEC_2_3: |
| 488 | CmdFrm.operand[14] = 1 << 5; |
| 489 | break; |
| 490 | case FEC_3_4: |
| 491 | CmdFrm.operand[14] = 2 << 5; |
| 492 | break; |
| 493 | case FEC_5_6: |
| 494 | CmdFrm.operand[14] = 3 << 5; |
| 495 | break; |
| 496 | case FEC_7_8: |
| 497 | CmdFrm.operand[14] = 4 << 5; |
| 498 | break; |
| 499 | case FEC_1_2: |
| 500 | default: |
| 501 | CmdFrm.operand[14] = 0x00; |
| 502 | break; |
| 503 | } |
| 504 | switch(params->u.ofdm.guard_interval) { |
| 505 | case GUARD_INTERVAL_1_16: |
| 506 | CmdFrm.operand[14] |= 1 << 3; |
| 507 | break; |
| 508 | case GUARD_INTERVAL_1_8: |
| 509 | CmdFrm.operand[14] |= 2 << 3; |
| 510 | break; |
| 511 | case GUARD_INTERVAL_1_4: |
| 512 | CmdFrm.operand[14] |= 3 << 3; |
| 513 | break; |
| 514 | case GUARD_INTERVAL_1_32: |
| 515 | case GUARD_INTERVAL_AUTO: |
| 516 | default: |
| 517 | break; |
| 518 | } |
| 519 | switch(params->u.ofdm.transmission_mode) { |
| 520 | case TRANSMISSION_MODE_8K: |
| 521 | CmdFrm.operand[14] |= 1 << 1; |
| 522 | break; |
| 523 | case TRANSMISSION_MODE_2K: |
| 524 | case TRANSMISSION_MODE_AUTO: |
| 525 | default: |
| 526 | break; |
| 527 | } |
| 528 | |
| 529 | CmdFrm.operand[15] = 0x00; // network_ID[0] |
| 530 | CmdFrm.operand[16] = 0x00; // network_ID[1] |
| 531 | CmdFrm.operand[17] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted |
| 532 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 533 | CmdFrm.length = 24; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 534 | } else { |
| 535 | CmdFrm.operand[7] = 0x00; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 536 | CmdFrm.operand[8] = 0x00; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 537 | CmdFrm.operand[9] = 0x00; |
| 538 | CmdFrm.operand[10] = 0x00; |
| 539 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 540 | CmdFrm.operand[11] = |
| 541 | (((params->frequency/4000) >> 16) & 0xFF) | (2 << 6); |
| 542 | CmdFrm.operand[12] = |
| 543 | ((params->frequency/4000) >> 8) & 0xFF; |
| 544 | CmdFrm.operand[13] = (params->frequency/4000) & 0xFF; |
| 545 | CmdFrm.operand[14] = |
| 546 | ((params->u.qpsk.symbol_rate/1000) >> 12) & 0xFF; |
| 547 | CmdFrm.operand[15] = |
| 548 | ((params->u.qpsk.symbol_rate/1000) >> 4) & 0xFF; |
| 549 | CmdFrm.operand[16] = |
| 550 | ((params->u.qpsk.symbol_rate/1000) << 4) & 0xF0; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 551 | CmdFrm.operand[17] = 0x00; |
| 552 | switch(params->u.qpsk.fec_inner) { |
| 553 | case FEC_1_2: |
| 554 | CmdFrm.operand[18] = 0x1; |
| 555 | break; |
| 556 | case FEC_2_3: |
| 557 | CmdFrm.operand[18] = 0x2; |
| 558 | break; |
| 559 | case FEC_3_4: |
| 560 | CmdFrm.operand[18] = 0x3; |
| 561 | break; |
| 562 | case FEC_5_6: |
| 563 | CmdFrm.operand[18] = 0x4; |
| 564 | break; |
| 565 | case FEC_7_8: |
| 566 | CmdFrm.operand[18] = 0x5; |
| 567 | break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 568 | case FEC_8_9: |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 569 | CmdFrm.operand[18] = 0x6; |
| 570 | break; |
| 571 | case FEC_4_5: |
| 572 | CmdFrm.operand[18] = 0x8; |
| 573 | break; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 574 | case FEC_AUTO: |
| 575 | default: |
| 576 | CmdFrm.operand[18] = 0x0; |
| 577 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 578 | switch(params->u.qam.modulation) { |
| 579 | case QAM_16: |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 580 | CmdFrm.operand[19] = 0x08; // modulation |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 581 | break; |
| 582 | case QAM_32: |
| 583 | CmdFrm.operand[19] = 0x10; // modulation |
| 584 | break; |
| 585 | case QAM_64: |
| 586 | CmdFrm.operand[19] = 0x18; // modulation |
| 587 | break; |
| 588 | case QAM_128: |
| 589 | CmdFrm.operand[19] = 0x20; // modulation |
| 590 | break; |
| 591 | case QAM_256: |
| 592 | CmdFrm.operand[19] = 0x28; // modulation |
| 593 | break; |
| 594 | case QAM_AUTO: |
| 595 | default: |
| 596 | CmdFrm.operand[19] = 0x00; // modulation |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 597 | } |
| 598 | CmdFrm.operand[20] = 0x00; |
| 599 | CmdFrm.operand[21] = 0x00; |
| 600 | CmdFrm.operand[22] = 0x00; // Nr_of_dsd_sel_specs = 0 - > No PIDs are transmitted |
| 601 | |
| 602 | CmdFrm.length=28; |
| 603 | } |
| 604 | } // AVCTuner_DSD_direct |
| 605 | |
| 606 | if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) |
| 607 | return k; |
| 608 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 609 | mdelay(500); |
| 610 | |
| 611 | if(status) |
| 612 | *status=RspFrm.operand[2]; |
| 613 | return 0; |
| 614 | } |
| 615 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 616 | int AVCTuner_SetPIDs(struct firesat *firesat, unsigned char pidc, u16 pid[]) |
| 617 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 618 | AVCCmdFrm CmdFrm; |
| 619 | AVCRspFrm RspFrm; |
| 620 | int pos,k; |
| 621 | |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 622 | if(pidc > 16 && pidc != 0xFF) |
| 623 | return -EINVAL; |
| 624 | |
| 625 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 626 | |
| 627 | CmdFrm.cts = AVC; |
| 628 | CmdFrm.ctype = CONTROL; |
| 629 | CmdFrm.sutyp = 0x5; |
| 630 | CmdFrm.suid = firesat->subunit; |
| 631 | CmdFrm.opcode = DSD; |
| 632 | |
| 633 | CmdFrm.operand[0] = 0; // source plug |
| 634 | CmdFrm.operand[1] = 0xD2; // subfunction replace |
| 635 | CmdFrm.operand[2] = 0x20; // system id = DVB |
| 636 | CmdFrm.operand[3] = 0x00; // antenna number |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 637 | CmdFrm.operand[4] = 0x00; // system_specific_multiplex selection_length |
| 638 | CmdFrm.operand[5] = pidc; // Nr_of_dsd_sel_specs |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 639 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 640 | pos=6; |
| 641 | if(pidc != 0xFF) { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 642 | for(k=0;k<pidc;k++) { |
| 643 | CmdFrm.operand[pos++] = 0x13; // flowfunction relay |
| 644 | CmdFrm.operand[pos++] = 0x80; // dsd_sel_spec_valid_flags -> PID |
| 645 | CmdFrm.operand[pos++] = (pid[k] >> 8) & 0x1F; |
| 646 | CmdFrm.operand[pos++] = pid[k] & 0xFF; |
| 647 | CmdFrm.operand[pos++] = 0x00; // tableID |
| 648 | CmdFrm.operand[pos++] = 0x00; // filter_length |
| 649 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 650 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 651 | |
| 652 | CmdFrm.length = pos+3; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 653 | if((pos+3)%4) |
| 654 | CmdFrm.length += 4 - ((pos+3)%4); |
| 655 | |
| 656 | if((k=AVCWrite(firesat,&CmdFrm,&RspFrm))) |
| 657 | return k; |
| 658 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 659 | mdelay(50); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 660 | return 0; |
| 661 | } |
| 662 | |
| 663 | int AVCTuner_GetTS(struct firesat *firesat){ |
| 664 | AVCCmdFrm CmdFrm; |
| 665 | AVCRspFrm RspFrm; |
| 666 | int k; |
| 667 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 668 | //printk(KERN_INFO "%s\n", __func__); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 669 | |
| 670 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 671 | |
| 672 | CmdFrm.cts = AVC; |
| 673 | CmdFrm.ctype = CONTROL; |
| 674 | CmdFrm.sutyp = 0x5; |
| 675 | CmdFrm.suid = firesat->subunit; |
| 676 | CmdFrm.opcode = DSIT; |
| 677 | |
| 678 | CmdFrm.operand[0] = 0; // source plug |
| 679 | CmdFrm.operand[1] = 0xD2; // subfunction replace |
| 680 | CmdFrm.operand[2] = 0xFF; //status |
| 681 | CmdFrm.operand[3] = 0x20; // system id = DVB |
| 682 | CmdFrm.operand[4] = 0x00; // antenna number |
| 683 | CmdFrm.operand[5] = 0x0; // system_specific_search_flags |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 684 | CmdFrm.operand[6] = (firesat->type == FireSAT_DVB_T)?0x0c:0x11; // system_specific_multiplex selection_length |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 685 | CmdFrm.operand[7] = 0x00; // valid_flags [0] |
| 686 | CmdFrm.operand[8] = 0x00; // valid_flags [1] |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 687 | CmdFrm.operand[7 + (firesat->type == FireSAT_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] | 688 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 689 | CmdFrm.length = (firesat->type == FireSAT_DVB_T)?24:28; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 690 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 691 | if ((k=AVCWrite(firesat, &CmdFrm, &RspFrm))) |
| 692 | return k; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 693 | |
| 694 | mdelay(250); |
| 695 | return 0; |
| 696 | } |
| 697 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 698 | int AVCIdentifySubunit(struct firesat *firesat) |
| 699 | { |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 700 | AVCCmdFrm CmdFrm; |
| 701 | AVCRspFrm RspFrm; |
| 702 | |
| 703 | memset(&CmdFrm,0,sizeof(AVCCmdFrm)); |
| 704 | |
| 705 | CmdFrm.cts = AVC; |
| 706 | CmdFrm.ctype = CONTROL; |
| 707 | CmdFrm.sutyp = 0x5; // tuner |
| 708 | CmdFrm.suid = firesat->subunit; |
| 709 | CmdFrm.opcode = READ_DESCRIPTOR; |
| 710 | |
| 711 | CmdFrm.operand[0]=DESCRIPTOR_SUBUNIT_IDENTIFIER; |
| 712 | CmdFrm.operand[1]=0xff; |
| 713 | CmdFrm.operand[2]=0x00; |
| 714 | CmdFrm.operand[3]=0x00; // length highbyte |
| 715 | CmdFrm.operand[4]=0x08; // length lowbyte |
| 716 | CmdFrm.operand[5]=0x00; // offset highbyte |
| 717 | CmdFrm.operand[6]=0x0d; // offset lowbyte |
| 718 | |
| 719 | CmdFrm.length=12; |
| 720 | |
| 721 | if(AVCWrite(firesat,&CmdFrm,&RspFrm)<0) |
| 722 | return -EIO; |
| 723 | |
| 724 | if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 725 | printk(KERN_ERR "%s: AVCWrite returned error code %d\n", |
| 726 | __func__, RspFrm.resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 727 | return -EINVAL; |
| 728 | } |
| 729 | if(((RspFrm.operand[3] << 8) + RspFrm.operand[4]) != 8) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 730 | printk(KERN_ERR "%s: Invalid response length\n", __func__); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 731 | return -EINVAL; |
| 732 | } |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 733 | return 0; |
| 734 | } |
| 735 | |
| 736 | int AVCTunerStatus(struct firesat *firesat, ANTENNA_INPUT_INFO *antenna_input_info) { |
| 737 | AVCCmdFrm CmdFrm; |
| 738 | AVCRspFrm RspFrm; |
| 739 | int length; |
| 740 | |
| 741 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 742 | |
| 743 | CmdFrm.cts=AVC; |
| 744 | CmdFrm.ctype=CONTROL; |
| 745 | CmdFrm.sutyp=0x05; // tuner |
| 746 | CmdFrm.suid=firesat->subunit; |
| 747 | CmdFrm.opcode=READ_DESCRIPTOR; |
| 748 | |
| 749 | CmdFrm.operand[0]=DESCRIPTOR_TUNER_STATUS; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 750 | CmdFrm.operand[1]=0xff; //read_result_status |
| 751 | CmdFrm.operand[2]=0x00; // reserver |
| 752 | CmdFrm.operand[3]=0;//sizeof(ANTENNA_INPUT_INFO) >> 8; |
| 753 | CmdFrm.operand[4]=0;//sizeof(ANTENNA_INPUT_INFO) & 0xFF; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 754 | CmdFrm.operand[5]=0x00; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 755 | CmdFrm.operand[6]=0x00; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 756 | CmdFrm.length=12; |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 757 | if (AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 758 | return -EIO; |
| 759 | |
| 760 | if(RspFrm.resp != STABLE && RspFrm.resp != ACCEPTED) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 761 | printk(KERN_ERR "%s: AVCWrite returned code %d\n", |
| 762 | __func__, RspFrm.resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 763 | return -EINVAL; |
| 764 | } |
| 765 | |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 766 | length = RspFrm.operand[9]; |
| 767 | if(RspFrm.operand[1] == 0x10 && length == sizeof(ANTENNA_INPUT_INFO)) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 768 | { |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 769 | memcpy(antenna_input_info, &RspFrm.operand[10], |
| 770 | sizeof(ANTENNA_INPUT_INFO)); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 771 | return 0; |
| 772 | } |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 773 | printk(KERN_ERR "%s: invalid tuner status (op=%d,length=%d) returned " |
| 774 | "from AVC\n", __func__, RspFrm.operand[1], length); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 775 | return -EINVAL; |
| 776 | } |
| 777 | |
| 778 | int AVCLNBControl(struct firesat *firesat, char voltage, char burst, |
| 779 | char conttone, char nrdiseq, |
| 780 | struct dvb_diseqc_master_cmd *diseqcmd) |
| 781 | { |
| 782 | AVCCmdFrm CmdFrm; |
| 783 | AVCRspFrm RspFrm; |
| 784 | int i,j; |
| 785 | |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 786 | printk(KERN_INFO "%s: voltage = %x, burst = %x, conttone = %x\n", |
| 787 | __func__, voltage, burst, conttone); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 788 | |
| 789 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 790 | |
| 791 | CmdFrm.cts=AVC; |
| 792 | CmdFrm.ctype=CONTROL; |
| 793 | CmdFrm.sutyp=0x05; |
| 794 | CmdFrm.suid=firesat->subunit; |
| 795 | CmdFrm.opcode=VENDOR; |
| 796 | |
| 797 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 798 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 799 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 800 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_LNB_CONTROL; |
| 801 | |
| 802 | CmdFrm.operand[4]=voltage; |
| 803 | CmdFrm.operand[5]=nrdiseq; |
| 804 | |
| 805 | i=6; |
| 806 | |
| 807 | for(j=0;j<nrdiseq;j++) { |
| 808 | int k; |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 809 | printk(KERN_INFO "%s: diseq %d len %x\n", |
| 810 | __func__, j, diseqcmd[j].msg_len); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 811 | CmdFrm.operand[i++]=diseqcmd[j].msg_len; |
| 812 | |
| 813 | for(k=0;k<diseqcmd[j].msg_len;k++) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 814 | printk(KERN_INFO "%s: diseq %d msg[%d] = %x\n", |
| 815 | __func__, j, k, diseqcmd[j].msg[k]); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 816 | CmdFrm.operand[i++]=diseqcmd[j].msg[k]; |
| 817 | } |
| 818 | } |
| 819 | |
| 820 | CmdFrm.operand[i++]=burst; |
| 821 | CmdFrm.operand[i++]=conttone; |
| 822 | |
| 823 | CmdFrm.length=i+3; |
| 824 | if((i+3)%4) |
| 825 | CmdFrm.length += 4 - ((i+3)%4); |
| 826 | |
| 827 | /* for(j=0;j<CmdFrm.length;j++) |
| 828 | printk(KERN_INFO "%s: CmdFrm.operand[%d]=0x%x\n",__func__,j,CmdFrm.operand[j]); |
| 829 | |
| 830 | printk(KERN_INFO "%s: cmdfrm.length = %u\n",__func__,CmdFrm.length); |
| 831 | */ |
| 832 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 833 | return -EIO; |
| 834 | |
| 835 | if(RspFrm.resp != ACCEPTED) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 836 | printk(KERN_ERR "%s: AVCWrite returned code %d\n", |
| 837 | __func__, RspFrm.resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 838 | return -EINVAL; |
| 839 | } |
| 840 | |
| 841 | return 0; |
| 842 | } |
| 843 | |
| 844 | int AVCSubUnitInfo(struct firesat *firesat, char *subunitcount) |
| 845 | { |
| 846 | AVCCmdFrm CmdFrm; |
| 847 | AVCRspFrm RspFrm; |
| 848 | |
| 849 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 850 | |
| 851 | CmdFrm.cts = AVC; |
| 852 | CmdFrm.ctype = STATUS; |
| 853 | CmdFrm.sutyp = 0x1f; |
| 854 | CmdFrm.suid = 0x7; |
| 855 | CmdFrm.opcode = SUBUNIT_Info; |
| 856 | |
| 857 | CmdFrm.operand[0] = 0x07; |
| 858 | CmdFrm.operand[1] = 0xff; |
| 859 | CmdFrm.operand[2] = 0xff; |
| 860 | CmdFrm.operand[3] = 0xff; |
| 861 | CmdFrm.operand[4] = 0xff; |
| 862 | |
| 863 | CmdFrm.length = 8; |
| 864 | |
| 865 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 866 | return -EIO; |
| 867 | |
| 868 | if(RspFrm.resp != STABLE) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 869 | printk(KERN_ERR "%s: AVCWrite returned code %d\n", |
| 870 | __func__, RspFrm.resp); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 871 | return -EINVAL; |
| 872 | } |
| 873 | |
| 874 | if(subunitcount) |
| 875 | *subunitcount = (RspFrm.operand[1] & 0x7) + 1; |
| 876 | |
| 877 | return 0; |
| 878 | } |
| 879 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 880 | int AVCRegisterRemoteControl(struct firesat *firesat) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 881 | { |
| 882 | AVCCmdFrm CmdFrm; |
| 883 | |
| 884 | // printk(KERN_INFO "%s\n",__func__); |
| 885 | |
| 886 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 887 | |
| 888 | CmdFrm.cts = AVC; |
| 889 | CmdFrm.ctype = NOTIFY; |
| 890 | CmdFrm.sutyp = 0x1f; |
| 891 | CmdFrm.suid = 0x7; |
| 892 | CmdFrm.opcode = VENDOR; |
| 893 | |
| 894 | CmdFrm.operand[0] = SFE_VENDOR_DE_COMPANYID_0; |
| 895 | CmdFrm.operand[1] = SFE_VENDOR_DE_COMPANYID_1; |
| 896 | CmdFrm.operand[2] = SFE_VENDOR_DE_COMPANYID_2; |
| 897 | CmdFrm.operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL; |
| 898 | |
| 899 | CmdFrm.length = 8; |
| 900 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 901 | return AVCWrite(firesat, &CmdFrm, NULL); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 902 | } |
| 903 | |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 904 | void avc_remote_ctrl_work(struct work_struct *work) |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 905 | { |
Stefan Richter | 612262a | 2008-08-26 00:17:30 +0200 | [diff] [blame^] | 906 | struct firesat *firesat = |
| 907 | container_of(work, struct firesat, remote_ctrl_work); |
| 908 | |
| 909 | /* Should it be rescheduled in failure cases? */ |
| 910 | AVCRegisterRemoteControl(firesat); |
Greg Kroah-Hartman | c81c8b6 | 2008-03-06 21:30:23 -0800 | [diff] [blame] | 911 | } |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 912 | |
| 913 | int AVCTuner_Host2Ca(struct firesat *firesat) |
| 914 | { |
| 915 | |
| 916 | AVCCmdFrm CmdFrm; |
| 917 | AVCRspFrm RspFrm; |
| 918 | |
| 919 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 920 | CmdFrm.cts = AVC; |
| 921 | CmdFrm.ctype = CONTROL; |
| 922 | CmdFrm.sutyp = 0x5; |
| 923 | CmdFrm.suid = firesat->subunit; |
| 924 | CmdFrm.opcode = VENDOR; |
| 925 | |
| 926 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 927 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 928 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 929 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 930 | CmdFrm.operand[4] = 0; // slot |
| 931 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 932 | CmdFrm.operand[6] = 0; // more/last |
| 933 | CmdFrm.operand[7] = 0; // length |
| 934 | CmdFrm.length = 12; |
| 935 | |
| 936 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 937 | return -EIO; |
| 938 | |
| 939 | return 0; |
| 940 | } |
| 941 | |
| 942 | static int get_ca_object_pos(AVCRspFrm *RspFrm) |
| 943 | { |
| 944 | int length = 1; |
| 945 | |
| 946 | // Check length of length field |
| 947 | if (RspFrm->operand[7] & 0x80) |
| 948 | length = (RspFrm->operand[7] & 0x7F) + 1; |
| 949 | return length + 7; |
| 950 | } |
| 951 | |
| 952 | static int get_ca_object_length(AVCRspFrm *RspFrm) |
| 953 | { |
| 954 | int size = 0; |
| 955 | int i; |
| 956 | |
| 957 | if (RspFrm->operand[7] & 0x80) { |
| 958 | for (i = 0; i < (RspFrm->operand[7] & 0x7F); i++) { |
| 959 | size <<= 8; |
| 960 | size += RspFrm->operand[8 + i]; |
| 961 | } |
| 962 | } |
| 963 | return RspFrm->operand[7]; |
| 964 | } |
| 965 | |
| 966 | int avc_ca_app_info(struct firesat *firesat, char *app_info, int *length) |
| 967 | { |
| 968 | AVCCmdFrm CmdFrm; |
| 969 | AVCRspFrm RspFrm; |
| 970 | int pos; |
| 971 | |
| 972 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 973 | CmdFrm.cts = AVC; |
| 974 | CmdFrm.ctype = STATUS; |
| 975 | CmdFrm.sutyp = 0x5; |
| 976 | CmdFrm.suid = firesat->subunit; |
| 977 | CmdFrm.opcode = VENDOR; |
| 978 | |
| 979 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 980 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 981 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 982 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 983 | CmdFrm.operand[4] = 0; // slot |
| 984 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 985 | CmdFrm.length = 12; |
| 986 | |
| 987 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 988 | return -EIO; |
| 989 | |
| 990 | |
| 991 | pos = get_ca_object_pos(&RspFrm); |
| 992 | app_info[0] = (TAG_APP_INFO >> 16) & 0xFF; |
| 993 | app_info[1] = (TAG_APP_INFO >> 8) & 0xFF; |
| 994 | app_info[2] = (TAG_APP_INFO >> 0) & 0xFF; |
| 995 | app_info[3] = 6 + RspFrm.operand[pos + 4]; |
| 996 | app_info[4] = 0x01; |
| 997 | memcpy(&app_info[5], &RspFrm.operand[pos], 5 + RspFrm.operand[pos + 4]); |
| 998 | *length = app_info[3] + 4; |
| 999 | |
| 1000 | return 0; |
| 1001 | } |
| 1002 | |
| 1003 | int avc_ca_info(struct firesat *firesat, char *app_info, int *length) |
| 1004 | { |
| 1005 | AVCCmdFrm CmdFrm; |
| 1006 | AVCRspFrm RspFrm; |
| 1007 | int pos; |
| 1008 | |
| 1009 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1010 | CmdFrm.cts = AVC; |
| 1011 | CmdFrm.ctype = STATUS; |
| 1012 | CmdFrm.sutyp = 0x5; |
| 1013 | CmdFrm.suid = firesat->subunit; |
| 1014 | CmdFrm.opcode = VENDOR; |
| 1015 | |
| 1016 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1017 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1018 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1019 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 1020 | CmdFrm.operand[4] = 0; // slot |
| 1021 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; // ca tag |
| 1022 | CmdFrm.length = 12; |
| 1023 | |
| 1024 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1025 | return -EIO; |
| 1026 | |
| 1027 | pos = get_ca_object_pos(&RspFrm); |
| 1028 | app_info[0] = (TAG_CA_INFO >> 16) & 0xFF; |
| 1029 | app_info[1] = (TAG_CA_INFO >> 8) & 0xFF; |
| 1030 | app_info[2] = (TAG_CA_INFO >> 0) & 0xFF; |
| 1031 | app_info[3] = 2; |
| 1032 | app_info[4] = app_info[5]; |
| 1033 | app_info[5] = app_info[6]; |
| 1034 | *length = app_info[3] + 4; |
| 1035 | |
| 1036 | return 0; |
| 1037 | } |
| 1038 | |
| 1039 | int avc_ca_reset(struct firesat *firesat) |
| 1040 | { |
| 1041 | AVCCmdFrm CmdFrm; |
| 1042 | AVCRspFrm RspFrm; |
| 1043 | |
| 1044 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1045 | CmdFrm.cts = AVC; |
| 1046 | CmdFrm.ctype = CONTROL; |
| 1047 | CmdFrm.sutyp = 0x5; |
| 1048 | CmdFrm.suid = firesat->subunit; |
| 1049 | CmdFrm.opcode = VENDOR; |
| 1050 | |
| 1051 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1052 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1053 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1054 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 1055 | CmdFrm.operand[4] = 0; // slot |
| 1056 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_RESET; // ca tag |
| 1057 | CmdFrm.operand[6] = 0; // more/last |
| 1058 | CmdFrm.operand[7] = 1; // length |
| 1059 | CmdFrm.operand[8] = 0; // force hardware reset |
| 1060 | CmdFrm.length = 12; |
| 1061 | |
| 1062 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1063 | return -EIO; |
| 1064 | |
| 1065 | return 0; |
| 1066 | } |
| 1067 | |
| 1068 | int avc_ca_pmt(struct firesat *firesat, char *msg, int length) |
| 1069 | { |
| 1070 | AVCCmdFrm CmdFrm; |
| 1071 | AVCRspFrm RspFrm; |
| 1072 | int list_management; |
| 1073 | int program_info_length; |
| 1074 | int pmt_cmd_id; |
| 1075 | int read_pos; |
| 1076 | int write_pos; |
| 1077 | int es_info_length; |
| 1078 | int crc32_csum; |
| 1079 | |
| 1080 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1081 | CmdFrm.cts = AVC; |
| 1082 | CmdFrm.ctype = CONTROL; |
| 1083 | CmdFrm.sutyp = 0x5; |
| 1084 | CmdFrm.suid = firesat->subunit; |
| 1085 | CmdFrm.opcode = VENDOR; |
| 1086 | |
| 1087 | if (msg[0] != LIST_MANAGEMENT_ONLY) { |
Henrik Kurelid | 81c67b7 | 2008-08-24 15:20:07 +0200 | [diff] [blame] | 1088 | printk(KERN_INFO "%s: list_management %d not support. " |
| 1089 | "Forcing list_management to \"only\" (3). \n", |
| 1090 | __func__, msg[0]); |
| 1091 | msg[0] = LIST_MANAGEMENT_ONLY; |
Henrik Kurelid | df4846c | 2008-08-01 10:00:45 +0200 | [diff] [blame] | 1092 | } |
| 1093 | // We take the cmd_id from the programme level only! |
| 1094 | list_management = msg[0]; |
| 1095 | program_info_length = ((msg[4] & 0x0F) << 8) + msg[5]; |
| 1096 | if (program_info_length > 0) |
| 1097 | program_info_length--; // Remove pmt_cmd_id |
| 1098 | pmt_cmd_id = msg[6]; |
| 1099 | |
| 1100 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1101 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1102 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1103 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 1104 | CmdFrm.operand[4] = 0; // slot |
| 1105 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_PMT; // ca tag |
| 1106 | CmdFrm.operand[6] = 0; // more/last |
| 1107 | //CmdFrm.operand[7] = XXXprogram_info_length + 17; // length |
| 1108 | CmdFrm.operand[8] = list_management; |
| 1109 | CmdFrm.operand[9] = 0x01; // pmt_cmd=OK_descramble |
| 1110 | |
| 1111 | // TS program map table |
| 1112 | |
| 1113 | // Table id=2 |
| 1114 | CmdFrm.operand[10] = 0x02; |
| 1115 | // Section syntax + length |
| 1116 | CmdFrm.operand[11] = 0x80; |
| 1117 | //CmdFrm.operand[12] = XXXprogram_info_length + 12; |
| 1118 | // Program number |
| 1119 | CmdFrm.operand[13] = msg[1]; |
| 1120 | CmdFrm.operand[14] = msg[2]; |
| 1121 | // Version number=0 + current/next=1 |
| 1122 | CmdFrm.operand[15] = 0x01; |
| 1123 | // Section number=0 |
| 1124 | CmdFrm.operand[16] = 0x00; |
| 1125 | // Last section number=0 |
| 1126 | CmdFrm.operand[17] = 0x00; |
| 1127 | // PCR_PID=1FFF |
| 1128 | CmdFrm.operand[18] = 0x1F; |
| 1129 | CmdFrm.operand[19] = 0xFF; |
| 1130 | // Program info length |
| 1131 | CmdFrm.operand[20] = (program_info_length >> 8); |
| 1132 | CmdFrm.operand[21] = (program_info_length & 0xFF); |
| 1133 | // CA descriptors at programme level |
| 1134 | read_pos = 6; |
| 1135 | write_pos = 22; |
| 1136 | if (program_info_length > 0) { |
| 1137 | /* printk(KERN_INFO "Copying descriptors at programme level.\n"); */ |
| 1138 | pmt_cmd_id = msg[read_pos++]; |
| 1139 | if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { |
| 1140 | printk(KERN_ERR "Invalid pmt_cmd_id=%d.\n", |
| 1141 | pmt_cmd_id); |
| 1142 | } |
| 1143 | memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], |
| 1144 | program_info_length); |
| 1145 | read_pos += program_info_length; |
| 1146 | write_pos += program_info_length; |
| 1147 | } |
| 1148 | while (read_pos < length) { |
| 1149 | /* printk(KERN_INFO "Copying descriptors at stream level for " */ |
| 1150 | /* "stream type %d.\n", msg[read_pos]); */ |
| 1151 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 1152 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 1153 | CmdFrm.operand[write_pos++] = msg[read_pos++]; |
| 1154 | es_info_length = |
| 1155 | ((msg[read_pos] & 0x0F) << 8) + msg[read_pos + 1]; |
| 1156 | read_pos += 2; |
| 1157 | if (es_info_length > 0) |
| 1158 | es_info_length--; // Remove pmt_cmd_id |
| 1159 | CmdFrm.operand[write_pos++] = es_info_length >> 8; |
| 1160 | CmdFrm.operand[write_pos++] = es_info_length & 0xFF; |
| 1161 | if (es_info_length > 0) { |
| 1162 | pmt_cmd_id = msg[read_pos++]; |
| 1163 | if (pmt_cmd_id != 1 && pmt_cmd_id !=4) { |
| 1164 | printk(KERN_ERR "Invalid pmt_cmd_id=%d at " |
| 1165 | "stream level.\n", pmt_cmd_id); |
| 1166 | } |
| 1167 | memcpy(&CmdFrm.operand[write_pos], &msg[read_pos], |
| 1168 | es_info_length); |
| 1169 | read_pos += es_info_length; |
| 1170 | write_pos += es_info_length; |
| 1171 | } |
| 1172 | } |
| 1173 | |
| 1174 | // CRC |
| 1175 | CmdFrm.operand[write_pos++] = 0x00; |
| 1176 | CmdFrm.operand[write_pos++] = 0x00; |
| 1177 | CmdFrm.operand[write_pos++] = 0x00; |
| 1178 | CmdFrm.operand[write_pos++] = 0x00; |
| 1179 | |
| 1180 | CmdFrm.operand[7] = write_pos - 8; |
| 1181 | CmdFrm.operand[12] = write_pos - 13; |
| 1182 | |
| 1183 | crc32_csum = crc32_be(0, &CmdFrm.operand[10], |
| 1184 | CmdFrm.operand[12] - 1); |
| 1185 | CmdFrm.operand[write_pos - 4] = (crc32_csum >> 24) & 0xFF; |
| 1186 | CmdFrm.operand[write_pos - 3] = (crc32_csum >> 16) & 0xFF; |
| 1187 | CmdFrm.operand[write_pos - 2] = (crc32_csum >> 8) & 0xFF; |
| 1188 | CmdFrm.operand[write_pos - 1] = (crc32_csum >> 0) & 0xFF; |
| 1189 | |
| 1190 | CmdFrm.length = write_pos + 3; |
| 1191 | if ((write_pos + 3) % 4) |
| 1192 | CmdFrm.length += 4 - ((write_pos + 3) % 4); |
| 1193 | |
| 1194 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1195 | return -EIO; |
| 1196 | |
| 1197 | if (RspFrm.resp != ACCEPTED) { |
| 1198 | printk(KERN_ERR "Answer to CA PMT was %d\n", RspFrm.resp); |
| 1199 | return -EFAULT; |
| 1200 | } |
| 1201 | |
| 1202 | return 0; |
| 1203 | |
| 1204 | } |
| 1205 | |
| 1206 | int avc_ca_get_time_date(struct firesat *firesat, int *interval) |
| 1207 | { |
| 1208 | AVCCmdFrm CmdFrm; |
| 1209 | AVCRspFrm RspFrm; |
| 1210 | |
| 1211 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1212 | CmdFrm.cts = AVC; |
| 1213 | CmdFrm.ctype = STATUS; |
| 1214 | CmdFrm.sutyp = 0x5; |
| 1215 | CmdFrm.suid = firesat->subunit; |
| 1216 | CmdFrm.opcode = VENDOR; |
| 1217 | |
| 1218 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1219 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1220 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1221 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 1222 | CmdFrm.operand[4] = 0; // slot |
| 1223 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; // ca tag |
| 1224 | CmdFrm.operand[6] = 0; // more/last |
| 1225 | CmdFrm.operand[7] = 0; // length |
| 1226 | CmdFrm.length = 12; |
| 1227 | |
| 1228 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1229 | return -EIO; |
| 1230 | |
| 1231 | *interval = RspFrm.operand[get_ca_object_pos(&RspFrm)]; |
| 1232 | |
| 1233 | return 0; |
| 1234 | } |
| 1235 | |
| 1236 | int avc_ca_enter_menu(struct firesat *firesat) |
| 1237 | { |
| 1238 | AVCCmdFrm CmdFrm; |
| 1239 | AVCRspFrm RspFrm; |
| 1240 | |
| 1241 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1242 | CmdFrm.cts = AVC; |
| 1243 | CmdFrm.ctype = STATUS; |
| 1244 | CmdFrm.sutyp = 0x5; |
| 1245 | CmdFrm.suid = firesat->subunit; |
| 1246 | CmdFrm.opcode = VENDOR; |
| 1247 | |
| 1248 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1249 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1250 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1251 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_HOST2CA; |
| 1252 | CmdFrm.operand[4] = 0; // slot |
| 1253 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU; |
| 1254 | CmdFrm.operand[6] = 0; // more/last |
| 1255 | CmdFrm.operand[7] = 0; // length |
| 1256 | CmdFrm.length = 12; |
| 1257 | |
| 1258 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1259 | return -EIO; |
| 1260 | |
| 1261 | return 0; |
| 1262 | } |
| 1263 | |
| 1264 | int avc_ca_get_mmi(struct firesat *firesat, char *mmi_object, int *length) |
| 1265 | { |
| 1266 | AVCCmdFrm CmdFrm; |
| 1267 | AVCRspFrm RspFrm; |
| 1268 | |
| 1269 | memset(&CmdFrm, 0, sizeof(AVCCmdFrm)); |
| 1270 | CmdFrm.cts = AVC; |
| 1271 | CmdFrm.ctype = STATUS; |
| 1272 | CmdFrm.sutyp = 0x5; |
| 1273 | CmdFrm.suid = firesat->subunit; |
| 1274 | CmdFrm.opcode = VENDOR; |
| 1275 | |
| 1276 | CmdFrm.operand[0]=SFE_VENDOR_DE_COMPANYID_0; |
| 1277 | CmdFrm.operand[1]=SFE_VENDOR_DE_COMPANYID_1; |
| 1278 | CmdFrm.operand[2]=SFE_VENDOR_DE_COMPANYID_2; |
| 1279 | CmdFrm.operand[3]=SFE_VENDOR_OPCODE_CA2HOST; |
| 1280 | CmdFrm.operand[4] = 0; // slot |
| 1281 | CmdFrm.operand[5] = SFE_VENDOR_TAG_CA_MMI; |
| 1282 | CmdFrm.operand[6] = 0; // more/last |
| 1283 | CmdFrm.operand[7] = 0; // length |
| 1284 | CmdFrm.length = 12; |
| 1285 | |
| 1286 | if(AVCWrite(firesat,&CmdFrm,&RspFrm) < 0) |
| 1287 | return -EIO; |
| 1288 | |
| 1289 | *length = get_ca_object_length(&RspFrm); |
| 1290 | memcpy(mmi_object, &RspFrm.operand[get_ca_object_pos(&RspFrm)], *length); |
| 1291 | |
| 1292 | return 0; |
| 1293 | } |