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