1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Abilis Systems Single DVB-T Receiver 4 * 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 AS10x 14 * @adap: pointer to AS10x bus adapter 15 * 16 * Return 0 when no error, < 0 in case of error. 17 */ 18 int 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 49 out: 50 return error; 51 } 52 53 /** 54 * as10x_cmd_turn_off - send turn off command to AS10x 55 * @adap: pointer to AS10x bus adapter 56 * 57 * Return 0 on success or negative value in case of error. 58 */ 59 int 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 89 out: 90 return error; 91 } 92 93 /** 94 * as10x_cmd_set_tune - send set tune command to AS10x 95 * @adap: pointer to AS10x bus adapter 96 * @ptune: tune parameters 97 * 98 * Return 0 on success or negative value in case of error. 99 */ 100 int 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 144 out: 145 return error; 146 } 147 148 /** 149 * as10x_cmd_get_tune_status - send get tune status command to AS10x 150 * @adap: pointer to AS10x bus adapter 151 * @pstatus: pointer to updated status structure of the current tune 152 * 153 * Return 0 on success or negative value in case of error. 154 */ 155 int 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 197 out: 198 return error; 199 } 200 201 /** 202 * as10x_cmd_get_tps - send get TPS command to AS10x 203 * @adap: pointer to AS10x handle 204 * @ptps: pointer to TPS parameters structure 205 * 206 * Return 0 on success or negative value in case of error. 207 */ 208 int 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 255 out: 256 return error; 257 } 258 259 /** 260 * as10x_cmd_get_demod_stats - send get demod stats command to AS10x 261 * @adap: pointer to AS10x bus adapter 262 * @pdemod_stats: pointer to demod stats parameters structure 263 * 264 * Return 0 on success or negative value in case of error. 265 */ 266 int 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 314 out: 315 return error; 316 } 317 318 /** 319 * as10x_cmd_get_impulse_resp - send get impulse response command to AS10x 320 * @adap: pointer to AS10x bus adapter 321 * @is_ready: pointer to value indicating when impulse 322 * response data is ready 323 * 324 * Return 0 on success or negative value in case of error. 325 */ 326 int 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 365 out: 366 return error; 367 } 368 369 /** 370 * as10x_cmd_build - build AS10x command header 371 * @pcmd: pointer to AS10x command buffer 372 * @xid: sequence id of the command 373 * @cmd_len: length of the command 374 */ 375 void 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 response 386 * @prsp: pointer to AS10x command buffer 387 * @proc_id: id of the command 388 * 389 * Return 0 on success or negative value in case of error. 390 */ 391 int 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