1/* 2 * Abilis Systems Single DVB-T Receiver 3 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> 4 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2, or (at your option) 9 * any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 */ 16 17#include <linux/kernel.h> 18#include "as102_drv.h" 19#include "as10x_cmd.h" 20 21/** 22 * as10x_cmd_turn_on - send turn on command to AS10x 23 * @adap: pointer to AS10x bus adapter 24 * 25 * Return 0 when no error, < 0 in case of error. 26 */ 27int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap) 28{ 29 int error = AS10X_CMD_ERROR; 30 struct as10x_cmd_t *pcmd, *prsp; 31 32 pcmd = adap->cmd; 33 prsp = adap->rsp; 34 35 /* prepare command */ 36 as10x_cmd_build(pcmd, (++adap->cmd_xid), 37 sizeof(pcmd->body.turn_on.req)); 38 39 /* fill command */ 40 pcmd->body.turn_on.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNON); 41 42 /* send command */ 43 if (adap->ops->xfer_cmd) { 44 error = adap->ops->xfer_cmd(adap, (uint8_t *) pcmd, 45 sizeof(pcmd->body.turn_on.req) + 46 HEADER_SIZE, 47 (uint8_t *) prsp, 48 sizeof(prsp->body.turn_on.rsp) + 49 HEADER_SIZE); 50 } 51 52 if (error < 0) 53 goto out; 54 55 /* parse response */ 56 error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP); 57 58out: 59 return error; 60} 61 62/** 63 * as10x_cmd_turn_off - send turn off command to AS10x 64 * @adap: pointer to AS10x bus adapter 65 * 66 * Return 0 on success or negative value in case of error. 67 */ 68int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap) 69{ 70 int error = AS10X_CMD_ERROR; 71 struct as10x_cmd_t *pcmd, *prsp; 72 73 pcmd = adap->cmd; 74 prsp = adap->rsp; 75 76 /* prepare command */ 77 as10x_cmd_build(pcmd, (++adap->cmd_xid), 78 sizeof(pcmd->body.turn_off.req)); 79 80 /* fill command */ 81 pcmd->body.turn_off.req.proc_id = cpu_to_le16(CONTROL_PROC_TURNOFF); 82 83 /* send command */ 84 if (adap->ops->xfer_cmd) { 85 error = adap->ops->xfer_cmd( 86 adap, (uint8_t *) pcmd, 87 sizeof(pcmd->body.turn_off.req) + HEADER_SIZE, 88 (uint8_t *) prsp, 89 sizeof(prsp->body.turn_off.rsp) + HEADER_SIZE); 90 } 91 92 if (error < 0) 93 goto out; 94 95 /* parse response */ 96 error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP); 97 98out: 99 return error; 100} 101 102/** 103 * as10x_cmd_set_tune - send set tune command to AS10x 104 * @adap: pointer to AS10x bus adapter 105 * @ptune: tune parameters 106 * 107 * Return 0 on success or negative value in case of error. 108 */ 109int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap, 110 struct as10x_tune_args *ptune) 111{ 112 int error = AS10X_CMD_ERROR; 113 struct as10x_cmd_t *preq, *prsp; 114 115 preq = adap->cmd; 116 prsp = adap->rsp; 117 118 /* prepare command */ 119 as10x_cmd_build(preq, (++adap->cmd_xid), 120 sizeof(preq->body.set_tune.req)); 121 122 /* fill command */ 123 preq->body.set_tune.req.proc_id = cpu_to_le16(CONTROL_PROC_SETTUNE); 124 preq->body.set_tune.req.args.freq = (__force __u32)cpu_to_le32(ptune->freq); 125 preq->body.set_tune.req.args.bandwidth = ptune->bandwidth; 126 preq->body.set_tune.req.args.hier_select = ptune->hier_select; 127 preq->body.set_tune.req.args.modulation = ptune->modulation; 128 preq->body.set_tune.req.args.hierarchy = ptune->hierarchy; 129 preq->body.set_tune.req.args.interleaving_mode = 130 ptune->interleaving_mode; 131 preq->body.set_tune.req.args.code_rate = ptune->code_rate; 132 preq->body.set_tune.req.args.guard_interval = ptune->guard_interval; 133 preq->body.set_tune.req.args.transmission_mode = 134 ptune->transmission_mode; 135 136 /* send command */ 137 if (adap->ops->xfer_cmd) { 138 error = adap->ops->xfer_cmd(adap, 139 (uint8_t *) preq, 140 sizeof(preq->body.set_tune.req) 141 + HEADER_SIZE, 142 (uint8_t *) prsp, 143 sizeof(prsp->body.set_tune.rsp) 144 + HEADER_SIZE); 145 } 146 147 if (error < 0) 148 goto out; 149 150 /* parse response */ 151 error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP); 152 153out: 154 return error; 155} 156 157/** 158 * as10x_cmd_get_tune_status - send get tune status command to AS10x 159 * @adap: pointer to AS10x bus adapter 160 * @pstatus: pointer to updated status structure of the current tune 161 * 162 * Return 0 on success or negative value in case of error. 163 */ 164int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap, 165 struct as10x_tune_status *pstatus) 166{ 167 int error = AS10X_CMD_ERROR; 168 struct as10x_cmd_t *preq, *prsp; 169 170 preq = adap->cmd; 171 prsp = adap->rsp; 172 173 /* prepare command */ 174 as10x_cmd_build(preq, (++adap->cmd_xid), 175 sizeof(preq->body.get_tune_status.req)); 176 177 /* fill command */ 178 preq->body.get_tune_status.req.proc_id = 179 cpu_to_le16(CONTROL_PROC_GETTUNESTAT); 180 181 /* send command */ 182 if (adap->ops->xfer_cmd) { 183 error = adap->ops->xfer_cmd( 184 adap, 185 (uint8_t *) preq, 186 sizeof(preq->body.get_tune_status.req) + HEADER_SIZE, 187 (uint8_t *) prsp, 188 sizeof(prsp->body.get_tune_status.rsp) + HEADER_SIZE); 189 } 190 191 if (error < 0) 192 goto out; 193 194 /* parse response */ 195 error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTUNESTAT_RSP); 196 if (error < 0) 197 goto out; 198 199 /* Response OK -> get response data */ 200 pstatus->tune_state = prsp->body.get_tune_status.rsp.sts.tune_state; 201 pstatus->signal_strength = 202 le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.signal_strength); 203 pstatus->PER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.PER); 204 pstatus->BER = le16_to_cpu((__force __le16)prsp->body.get_tune_status.rsp.sts.BER); 205 206out: 207 return error; 208} 209 210/** 211 * as10x_cmd_get_tps - send get TPS command to AS10x 212 * @adap: pointer to AS10x handle 213 * @ptps: pointer to TPS parameters structure 214 * 215 * Return 0 on success or negative value in case of error. 216 */ 217int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps) 218{ 219 int error = AS10X_CMD_ERROR; 220 struct as10x_cmd_t *pcmd, *prsp; 221 222 pcmd = adap->cmd; 223 prsp = adap->rsp; 224 225 /* prepare command */ 226 as10x_cmd_build(pcmd, (++adap->cmd_xid), 227 sizeof(pcmd->body.get_tps.req)); 228 229 /* fill command */ 230 pcmd->body.get_tune_status.req.proc_id = 231 cpu_to_le16(CONTROL_PROC_GETTPS); 232 233 /* send command */ 234 if (adap->ops->xfer_cmd) { 235 error = adap->ops->xfer_cmd(adap, 236 (uint8_t *) pcmd, 237 sizeof(pcmd->body.get_tps.req) + 238 HEADER_SIZE, 239 (uint8_t *) prsp, 240 sizeof(prsp->body.get_tps.rsp) + 241 HEADER_SIZE); 242 } 243 244 if (error < 0) 245 goto out; 246 247 /* parse response */ 248 error = as10x_rsp_parse(prsp, CONTROL_PROC_GETTPS_RSP); 249 if (error < 0) 250 goto out; 251 252 /* Response OK -> get response data */ 253 ptps->modulation = prsp->body.get_tps.rsp.tps.modulation; 254 ptps->hierarchy = prsp->body.get_tps.rsp.tps.hierarchy; 255 ptps->interleaving_mode = prsp->body.get_tps.rsp.tps.interleaving_mode; 256 ptps->code_rate_HP = prsp->body.get_tps.rsp.tps.code_rate_HP; 257 ptps->code_rate_LP = prsp->body.get_tps.rsp.tps.code_rate_LP; 258 ptps->guard_interval = prsp->body.get_tps.rsp.tps.guard_interval; 259 ptps->transmission_mode = prsp->body.get_tps.rsp.tps.transmission_mode; 260 ptps->DVBH_mask_HP = prsp->body.get_tps.rsp.tps.DVBH_mask_HP; 261 ptps->DVBH_mask_LP = prsp->body.get_tps.rsp.tps.DVBH_mask_LP; 262 ptps->cell_ID = le16_to_cpu((__force __le16)prsp->body.get_tps.rsp.tps.cell_ID); 263 264out: 265 return error; 266} 267 268/** 269 * as10x_cmd_get_demod_stats - send get demod stats command to AS10x 270 * @adap: pointer to AS10x bus adapter 271 * @pdemod_stats: pointer to demod stats parameters structure 272 * 273 * Return 0 on success or negative value in case of error. 274 */ 275int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap, 276 struct as10x_demod_stats *pdemod_stats) 277{ 278 int error = AS10X_CMD_ERROR; 279 struct as10x_cmd_t *pcmd, *prsp; 280 281 pcmd = adap->cmd; 282 prsp = adap->rsp; 283 284 /* prepare command */ 285 as10x_cmd_build(pcmd, (++adap->cmd_xid), 286 sizeof(pcmd->body.get_demod_stats.req)); 287 288 /* fill command */ 289 pcmd->body.get_demod_stats.req.proc_id = 290 cpu_to_le16(CONTROL_PROC_GET_DEMOD_STATS); 291 292 /* send command */ 293 if (adap->ops->xfer_cmd) { 294 error = adap->ops->xfer_cmd(adap, 295 (uint8_t *) pcmd, 296 sizeof(pcmd->body.get_demod_stats.req) 297 + HEADER_SIZE, 298 (uint8_t *) prsp, 299 sizeof(prsp->body.get_demod_stats.rsp) 300 + HEADER_SIZE); 301 } 302 303 if (error < 0) 304 goto out; 305 306 /* parse response */ 307 error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_DEMOD_STATS_RSP); 308 if (error < 0) 309 goto out; 310 311 /* Response OK -> get response data */ 312 pdemod_stats->frame_count = 313 le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.frame_count); 314 pdemod_stats->bad_frame_count = 315 le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bad_frame_count); 316 pdemod_stats->bytes_fixed_by_rs = 317 le32_to_cpu((__force __le32)prsp->body.get_demod_stats.rsp.stats.bytes_fixed_by_rs); 318 pdemod_stats->mer = 319 le16_to_cpu((__force __le16)prsp->body.get_demod_stats.rsp.stats.mer); 320 pdemod_stats->has_started = 321 prsp->body.get_demod_stats.rsp.stats.has_started; 322 323out: 324 return error; 325} 326 327/** 328 * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x 329 * @adap: pointer to AS10x bus adapter 330 * @is_ready: pointer to value indicating when impulse 331 * response data is ready 332 * 333 * Return 0 on success or negative value in case of error. 334 */ 335int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap, 336 uint8_t *is_ready) 337{ 338 int error = AS10X_CMD_ERROR; 339 struct as10x_cmd_t *pcmd, *prsp; 340 341 pcmd = adap->cmd; 342 prsp = adap->rsp; 343 344 /* prepare command */ 345 as10x_cmd_build(pcmd, (++adap->cmd_xid), 346 sizeof(pcmd->body.get_impulse_rsp.req)); 347 348 /* fill command */ 349 pcmd->body.get_impulse_rsp.req.proc_id = 350 cpu_to_le16(CONTROL_PROC_GET_IMPULSE_RESP); 351 352 /* send command */ 353 if (adap->ops->xfer_cmd) { 354 error = adap->ops->xfer_cmd(adap, 355 (uint8_t *) pcmd, 356 sizeof(pcmd->body.get_impulse_rsp.req) 357 + HEADER_SIZE, 358 (uint8_t *) prsp, 359 sizeof(prsp->body.get_impulse_rsp.rsp) 360 + HEADER_SIZE); 361 } 362 363 if (error < 0) 364 goto out; 365 366 /* parse response */ 367 error = as10x_rsp_parse(prsp, CONTROL_PROC_GET_IMPULSE_RESP_RSP); 368 if (error < 0) 369 goto out; 370 371 /* Response OK -> get response data */ 372 *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready; 373 374out: 375 return error; 376} 377 378/** 379 * as10x_cmd_build - build AS10x command header 380 * @pcmd: pointer to AS10x command buffer 381 * @xid: sequence id of the command 382 * @cmd_len: length of the command 383 */ 384void as10x_cmd_build(struct as10x_cmd_t *pcmd, 385 uint16_t xid, uint16_t cmd_len) 386{ 387 pcmd->header.req_id = cpu_to_le16(xid); 388 pcmd->header.prog = cpu_to_le16(SERVICE_PROG_ID); 389 pcmd->header.version = cpu_to_le16(SERVICE_PROG_VERSION); 390 pcmd->header.data_len = cpu_to_le16(cmd_len); 391} 392 393/** 394 * as10x_rsp_parse - Parse command response 395 * @prsp: pointer to AS10x command buffer 396 * @proc_id: id of the command 397 * 398 * Return 0 on success or negative value in case of error. 399 */ 400int as10x_rsp_parse(struct as10x_cmd_t *prsp, uint16_t proc_id) 401{ 402 int error; 403 404 /* extract command error code */ 405 error = prsp->body.common.rsp.error; 406 407 if ((error == 0) && 408 (le16_to_cpu(prsp->body.common.rsp.proc_id) == proc_id)) { 409 return 0; 410 } 411 412 return AS10X_CMD_ERROR; 413} 414