Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/media/dvb/siano/smsdvb.c
15111 views
1
/****************************************************************
2
3
Siano Mobile Silicon, Inc.
4
MDTV receiver kernel modules.
5
Copyright (C) 2006-2008, Uri Shkolnik
6
7
This program is free software: you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation, either version 2 of the License, or
10
(at your option) any later version.
11
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
16
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
****************************************************************/
21
22
#include <linux/module.h>
23
#include <linux/slab.h>
24
#include <linux/init.h>
25
26
#include "dmxdev.h"
27
#include "dvbdev.h"
28
#include "dvb_demux.h"
29
#include "dvb_frontend.h"
30
31
#include "smscoreapi.h"
32
#include "smsendian.h"
33
#include "sms-cards.h"
34
35
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36
37
struct smsdvb_client_t {
38
struct list_head entry;
39
40
struct smscore_device_t *coredev;
41
struct smscore_client_t *smsclient;
42
43
struct dvb_adapter adapter;
44
struct dvb_demux demux;
45
struct dmxdev dmxdev;
46
struct dvb_frontend frontend;
47
48
fe_status_t fe_status;
49
50
struct completion tune_done;
51
52
/* todo: save freq/band instead whole struct */
53
struct dvb_frontend_parameters fe_params;
54
55
struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
56
int event_fe_state;
57
int event_unc_state;
58
};
59
60
static struct list_head g_smsdvb_clients;
61
static struct mutex g_smsdvb_clientslock;
62
63
static int sms_dbg;
64
module_param_named(debug, sms_dbg, int, 0644);
65
MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
66
67
/* Events that may come from DVB v3 adapter */
68
static void sms_board_dvb3_event(struct smsdvb_client_t *client,
69
enum SMS_DVB3_EVENTS event) {
70
71
struct smscore_device_t *coredev = client->coredev;
72
switch (event) {
73
case DVB3_EVENT_INIT:
74
sms_debug("DVB3_EVENT_INIT");
75
sms_board_event(coredev, BOARD_EVENT_BIND);
76
break;
77
case DVB3_EVENT_SLEEP:
78
sms_debug("DVB3_EVENT_SLEEP");
79
sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
80
break;
81
case DVB3_EVENT_HOTPLUG:
82
sms_debug("DVB3_EVENT_HOTPLUG");
83
sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
84
break;
85
case DVB3_EVENT_FE_LOCK:
86
if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
87
client->event_fe_state = DVB3_EVENT_FE_LOCK;
88
sms_debug("DVB3_EVENT_FE_LOCK");
89
sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
90
}
91
break;
92
case DVB3_EVENT_FE_UNLOCK:
93
if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
94
client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
95
sms_debug("DVB3_EVENT_FE_UNLOCK");
96
sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
97
}
98
break;
99
case DVB3_EVENT_UNC_OK:
100
if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
101
client->event_unc_state = DVB3_EVENT_UNC_OK;
102
sms_debug("DVB3_EVENT_UNC_OK");
103
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
104
}
105
break;
106
case DVB3_EVENT_UNC_ERR:
107
if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
108
client->event_unc_state = DVB3_EVENT_UNC_ERR;
109
sms_debug("DVB3_EVENT_UNC_ERR");
110
sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
111
}
112
break;
113
114
default:
115
sms_err("Unknown dvb3 api event");
116
break;
117
}
118
}
119
120
121
static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
122
struct SMSHOSTLIB_STATISTICS_ST *p)
123
{
124
if (sms_dbg & 2) {
125
printk(KERN_DEBUG "Reserved = %d", p->Reserved);
126
printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
127
printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
128
printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
129
printk(KERN_DEBUG "SNR = %d", p->SNR);
130
printk(KERN_DEBUG "BER = %d", p->BER);
131
printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
132
printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
133
printk(KERN_DEBUG "MFER = %d", p->MFER);
134
printk(KERN_DEBUG "RSSI = %d", p->RSSI);
135
printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
136
printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
137
printk(KERN_DEBUG "Frequency = %d", p->Frequency);
138
printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
139
printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
140
printk(KERN_DEBUG "ModemState = %d", p->ModemState);
141
printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
142
printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
143
printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
144
printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
145
printk(KERN_DEBUG "Constellation = %d", p->Constellation);
146
printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
147
printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
148
printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
149
printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
150
printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
151
printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
152
printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
153
printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
154
printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
155
printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
156
printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
157
printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
158
printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
159
printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
160
printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
161
printk(KERN_DEBUG "PreBER = %d", p->PreBER);
162
printk(KERN_DEBUG "CellId = %d", p->CellId);
163
printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
164
printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
165
printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
166
}
167
168
pReceptionData->IsDemodLocked = p->IsDemodLocked;
169
170
pReceptionData->SNR = p->SNR;
171
pReceptionData->BER = p->BER;
172
pReceptionData->BERErrorCount = p->BERErrorCount;
173
pReceptionData->InBandPwr = p->InBandPwr;
174
pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
175
};
176
177
178
static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
179
struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
180
{
181
int i;
182
183
if (sms_dbg & 2) {
184
printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
185
printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
186
printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
187
printk(KERN_DEBUG "SNR = %d", p->SNR);
188
printk(KERN_DEBUG "RSSI = %d", p->RSSI);
189
printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
190
printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
191
printk(KERN_DEBUG "Frequency = %d", p->Frequency);
192
printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
193
printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
194
printk(KERN_DEBUG "ModemState = %d", p->ModemState);
195
printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
196
printk(KERN_DEBUG "SystemType = %d", p->SystemType);
197
printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
198
printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
199
printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
200
201
for (i = 0; i < 3; i++) {
202
printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
203
printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
204
printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
205
printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
206
printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
207
printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
208
printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
209
printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
210
printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
211
printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
212
printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
213
printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
214
}
215
}
216
217
pReceptionData->IsDemodLocked = p->IsDemodLocked;
218
219
pReceptionData->SNR = p->SNR;
220
pReceptionData->InBandPwr = p->InBandPwr;
221
222
pReceptionData->ErrorTSPackets = 0;
223
pReceptionData->BER = 0;
224
pReceptionData->BERErrorCount = 0;
225
for (i = 0; i < 3; i++) {
226
pReceptionData->BER += p->LayerInfo[i].BER;
227
pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
228
pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
229
}
230
}
231
232
static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
233
{
234
struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
235
struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
236
+ cb->offset);
237
u32 *pMsgData = (u32 *) phdr + 1;
238
/*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
239
bool is_status_update = false;
240
241
smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
242
243
switch (phdr->msgType) {
244
case MSG_SMS_DVBT_BDA_DATA:
245
dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
246
cb->size - sizeof(struct SmsMsgHdr_ST));
247
break;
248
249
case MSG_SMS_RF_TUNE_RES:
250
case MSG_SMS_ISDBT_TUNE_RES:
251
complete(&client->tune_done);
252
break;
253
254
case MSG_SMS_SIGNAL_DETECTED_IND:
255
sms_info("MSG_SMS_SIGNAL_DETECTED_IND");
256
client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
257
is_status_update = true;
258
break;
259
260
case MSG_SMS_NO_SIGNAL_IND:
261
sms_info("MSG_SMS_NO_SIGNAL_IND");
262
client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
263
is_status_update = true;
264
break;
265
266
case MSG_SMS_TRANSMISSION_IND: {
267
sms_info("MSG_SMS_TRANSMISSION_IND");
268
269
pMsgData++;
270
memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
271
sizeof(struct TRANSMISSION_STATISTICS_S));
272
273
/* Mo need to correct guard interval
274
* (as opposed to old statistics message).
275
*/
276
CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
277
CORRECT_STAT_TRANSMISSON_MODE(
278
client->sms_stat_dvb.TransmissionData);
279
is_status_update = true;
280
break;
281
}
282
case MSG_SMS_HO_PER_SLICES_IND: {
283
struct RECEPTION_STATISTICS_S *pReceptionData =
284
&client->sms_stat_dvb.ReceptionData;
285
struct SRVM_SIGNAL_STATUS_S SignalStatusData;
286
287
/*sms_info("MSG_SMS_HO_PER_SLICES_IND");*/
288
pMsgData++;
289
SignalStatusData.result = pMsgData[0];
290
SignalStatusData.snr = pMsgData[1];
291
SignalStatusData.inBandPower = (s32) pMsgData[2];
292
SignalStatusData.tsPackets = pMsgData[3];
293
SignalStatusData.etsPackets = pMsgData[4];
294
SignalStatusData.constellation = pMsgData[5];
295
SignalStatusData.hpCode = pMsgData[6];
296
SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
297
SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
298
SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
299
SignalStatusData.reason = pMsgData[10];
300
SignalStatusData.requestId = pMsgData[11];
301
pReceptionData->IsRfLocked = pMsgData[16];
302
pReceptionData->IsDemodLocked = pMsgData[17];
303
pReceptionData->ModemState = pMsgData[12];
304
pReceptionData->SNR = pMsgData[1];
305
pReceptionData->BER = pMsgData[13];
306
pReceptionData->RSSI = pMsgData[14];
307
CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
308
309
pReceptionData->InBandPwr = (s32) pMsgData[2];
310
pReceptionData->CarrierOffset = (s32) pMsgData[15];
311
pReceptionData->TotalTSPackets = pMsgData[3];
312
pReceptionData->ErrorTSPackets = pMsgData[4];
313
314
/* TS PER */
315
if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
316
> 0) {
317
pReceptionData->TS_PER = (SignalStatusData.etsPackets
318
* 100) / (SignalStatusData.tsPackets
319
+ SignalStatusData.etsPackets);
320
} else {
321
pReceptionData->TS_PER = 0;
322
}
323
324
pReceptionData->BERBitCount = pMsgData[18];
325
pReceptionData->BERErrorCount = pMsgData[19];
326
327
pReceptionData->MRC_SNR = pMsgData[20];
328
pReceptionData->MRC_InBandPwr = pMsgData[21];
329
pReceptionData->MRC_RSSI = pMsgData[22];
330
331
is_status_update = true;
332
break;
333
}
334
case MSG_SMS_GET_STATISTICS_RES: {
335
union {
336
struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
337
struct SmsMsgStatisticsInfo_ST dvb;
338
} *p = (void *) (phdr + 1);
339
struct RECEPTION_STATISTICS_S *pReceptionData =
340
&client->sms_stat_dvb.ReceptionData;
341
342
sms_info("MSG_SMS_GET_STATISTICS_RES");
343
344
is_status_update = true;
345
346
switch (smscore_get_device_mode(client->coredev)) {
347
case DEVICE_MODE_ISDBT:
348
case DEVICE_MODE_ISDBT_BDA:
349
smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
350
break;
351
default:
352
smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
353
}
354
if (!pReceptionData->IsDemodLocked) {
355
pReceptionData->SNR = 0;
356
pReceptionData->BER = 0;
357
pReceptionData->BERErrorCount = 0;
358
pReceptionData->InBandPwr = 0;
359
pReceptionData->ErrorTSPackets = 0;
360
}
361
362
complete(&client->tune_done);
363
break;
364
}
365
default:
366
sms_info("Unhandled message %d", phdr->msgType);
367
368
}
369
smscore_putbuffer(client->coredev, cb);
370
371
if (is_status_update) {
372
if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
373
client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
374
| FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
375
sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
376
if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
377
== 0)
378
sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
379
else
380
sms_board_dvb3_event(client,
381
DVB3_EVENT_UNC_ERR);
382
383
} else {
384
if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
385
client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
386
else
387
client->fe_status = 0;
388
sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
389
}
390
}
391
392
return 0;
393
}
394
395
static void smsdvb_unregister_client(struct smsdvb_client_t *client)
396
{
397
/* must be called under clientslock */
398
399
list_del(&client->entry);
400
401
smscore_unregister_client(client->smsclient);
402
dvb_unregister_frontend(&client->frontend);
403
dvb_dmxdev_release(&client->dmxdev);
404
dvb_dmx_release(&client->demux);
405
dvb_unregister_adapter(&client->adapter);
406
kfree(client);
407
}
408
409
static void smsdvb_onremove(void *context)
410
{
411
kmutex_lock(&g_smsdvb_clientslock);
412
413
smsdvb_unregister_client((struct smsdvb_client_t *) context);
414
415
kmutex_unlock(&g_smsdvb_clientslock);
416
}
417
418
static int smsdvb_start_feed(struct dvb_demux_feed *feed)
419
{
420
struct smsdvb_client_t *client =
421
container_of(feed->demux, struct smsdvb_client_t, demux);
422
struct SmsMsgData_ST PidMsg;
423
424
sms_debug("add pid %d(%x)",
425
feed->pid, feed->pid);
426
427
PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
428
PidMsg.xMsgHeader.msgDstId = HIF_TASK;
429
PidMsg.xMsgHeader.msgFlags = 0;
430
PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
431
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
432
PidMsg.msgData[0] = feed->pid;
433
434
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
435
return smsclient_sendrequest(client->smsclient,
436
&PidMsg, sizeof(PidMsg));
437
}
438
439
static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
440
{
441
struct smsdvb_client_t *client =
442
container_of(feed->demux, struct smsdvb_client_t, demux);
443
struct SmsMsgData_ST PidMsg;
444
445
sms_debug("remove pid %d(%x)",
446
feed->pid, feed->pid);
447
448
PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
449
PidMsg.xMsgHeader.msgDstId = HIF_TASK;
450
PidMsg.xMsgHeader.msgFlags = 0;
451
PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
452
PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
453
PidMsg.msgData[0] = feed->pid;
454
455
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
456
return smsclient_sendrequest(client->smsclient,
457
&PidMsg, sizeof(PidMsg));
458
}
459
460
static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
461
void *buffer, size_t size,
462
struct completion *completion)
463
{
464
int rc;
465
466
smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
467
rc = smsclient_sendrequest(client->smsclient, buffer, size);
468
if (rc < 0)
469
return rc;
470
471
return wait_for_completion_timeout(completion,
472
msecs_to_jiffies(2000)) ?
473
0 : -ETIME;
474
}
475
476
static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
477
{
478
int rc;
479
struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
480
DVBT_BDA_CONTROL_MSG_ID,
481
HIF_TASK,
482
sizeof(struct SmsMsgHdr_ST), 0 };
483
484
rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
485
&client->tune_done);
486
487
return rc;
488
}
489
490
static inline int led_feedback(struct smsdvb_client_t *client)
491
{
492
if (client->fe_status & FE_HAS_LOCK)
493
return sms_board_led_feedback(client->coredev,
494
(client->sms_stat_dvb.ReceptionData.BER
495
== 0) ? SMS_LED_HI : SMS_LED_LO);
496
else
497
return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
498
}
499
500
static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
501
{
502
int rc;
503
struct smsdvb_client_t *client;
504
client = container_of(fe, struct smsdvb_client_t, frontend);
505
506
rc = smsdvb_send_statistics_request(client);
507
508
*stat = client->fe_status;
509
510
led_feedback(client);
511
512
return rc;
513
}
514
515
static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
516
{
517
int rc;
518
struct smsdvb_client_t *client;
519
client = container_of(fe, struct smsdvb_client_t, frontend);
520
521
rc = smsdvb_send_statistics_request(client);
522
523
*ber = client->sms_stat_dvb.ReceptionData.BER;
524
525
led_feedback(client);
526
527
return rc;
528
}
529
530
static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
531
{
532
int rc;
533
534
struct smsdvb_client_t *client;
535
client = container_of(fe, struct smsdvb_client_t, frontend);
536
537
rc = smsdvb_send_statistics_request(client);
538
539
if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
540
*strength = 0;
541
else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
542
*strength = 100;
543
else
544
*strength =
545
(client->sms_stat_dvb.ReceptionData.InBandPwr
546
+ 95) * 3 / 2;
547
548
led_feedback(client);
549
550
return rc;
551
}
552
553
static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
554
{
555
int rc;
556
struct smsdvb_client_t *client;
557
client = container_of(fe, struct smsdvb_client_t, frontend);
558
559
rc = smsdvb_send_statistics_request(client);
560
561
*snr = client->sms_stat_dvb.ReceptionData.SNR;
562
563
led_feedback(client);
564
565
return rc;
566
}
567
568
static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
569
{
570
int rc;
571
struct smsdvb_client_t *client;
572
client = container_of(fe, struct smsdvb_client_t, frontend);
573
574
rc = smsdvb_send_statistics_request(client);
575
576
*ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
577
578
led_feedback(client);
579
580
return rc;
581
}
582
583
static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
584
struct dvb_frontend_tune_settings *tune)
585
{
586
sms_debug("");
587
588
tune->min_delay_ms = 400;
589
tune->step_size = 250000;
590
tune->max_drift = 0;
591
return 0;
592
}
593
594
static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe,
595
struct dvb_frontend_parameters *p)
596
{
597
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
598
struct smsdvb_client_t *client =
599
container_of(fe, struct smsdvb_client_t, frontend);
600
601
struct {
602
struct SmsMsgHdr_ST Msg;
603
u32 Data[3];
604
} Msg;
605
606
int ret;
607
608
client->fe_status = FE_HAS_SIGNAL;
609
client->event_fe_state = -1;
610
client->event_unc_state = -1;
611
fe->dtv_property_cache.delivery_system = SYS_DVBT;
612
613
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
614
Msg.Msg.msgDstId = HIF_TASK;
615
Msg.Msg.msgFlags = 0;
616
Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
617
Msg.Msg.msgLength = sizeof(Msg);
618
Msg.Data[0] = c->frequency;
619
Msg.Data[2] = 12000000;
620
621
sms_info("%s: freq %d band %d", __func__, c->frequency,
622
c->bandwidth_hz);
623
624
switch (c->bandwidth_hz / 1000000) {
625
case 8:
626
Msg.Data[1] = BW_8_MHZ;
627
break;
628
case 7:
629
Msg.Data[1] = BW_7_MHZ;
630
break;
631
case 6:
632
Msg.Data[1] = BW_6_MHZ;
633
break;
634
case 0:
635
return -EOPNOTSUPP;
636
default:
637
return -EINVAL;
638
}
639
/* Disable LNA, if any. An error is returned if no LNA is present */
640
ret = sms_board_lna_control(client->coredev, 0);
641
if (ret == 0) {
642
fe_status_t status;
643
644
/* tune with LNA off at first */
645
ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
646
&client->tune_done);
647
648
smsdvb_read_status(fe, &status);
649
650
if (status & FE_HAS_LOCK)
651
return ret;
652
653
/* previous tune didn't lock - enable LNA and tune again */
654
sms_board_lna_control(client->coredev, 1);
655
}
656
657
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
658
&client->tune_done);
659
}
660
661
static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe,
662
struct dvb_frontend_parameters *p)
663
{
664
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
665
struct smsdvb_client_t *client =
666
container_of(fe, struct smsdvb_client_t, frontend);
667
668
struct {
669
struct SmsMsgHdr_ST Msg;
670
u32 Data[4];
671
} Msg;
672
673
fe->dtv_property_cache.delivery_system = SYS_ISDBT;
674
675
Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
676
Msg.Msg.msgDstId = HIF_TASK;
677
Msg.Msg.msgFlags = 0;
678
Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
679
Msg.Msg.msgLength = sizeof(Msg);
680
681
if (c->isdbt_sb_segment_idx == -1)
682
c->isdbt_sb_segment_idx = 0;
683
684
switch (c->isdbt_sb_segment_count) {
685
case 3:
686
Msg.Data[1] = BW_ISDBT_3SEG;
687
break;
688
case 1:
689
Msg.Data[1] = BW_ISDBT_1SEG;
690
break;
691
case 0: /* AUTO */
692
switch (c->bandwidth_hz / 1000000) {
693
case 8:
694
case 7:
695
c->isdbt_sb_segment_count = 3;
696
Msg.Data[1] = BW_ISDBT_3SEG;
697
break;
698
case 6:
699
c->isdbt_sb_segment_count = 1;
700
Msg.Data[1] = BW_ISDBT_1SEG;
701
break;
702
default: /* Assumes 6 MHZ bw */
703
c->isdbt_sb_segment_count = 1;
704
c->bandwidth_hz = 6000;
705
Msg.Data[1] = BW_ISDBT_1SEG;
706
break;
707
}
708
break;
709
default:
710
sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
711
return -EINVAL;
712
}
713
714
Msg.Data[0] = c->frequency;
715
Msg.Data[2] = 12000000;
716
Msg.Data[3] = c->isdbt_sb_segment_idx;
717
718
sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
719
c->frequency, c->isdbt_sb_segment_count,
720
c->isdbt_sb_segment_idx);
721
722
return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
723
&client->tune_done);
724
}
725
726
static int smsdvb_set_frontend(struct dvb_frontend *fe,
727
struct dvb_frontend_parameters *fep)
728
{
729
struct smsdvb_client_t *client =
730
container_of(fe, struct smsdvb_client_t, frontend);
731
struct smscore_device_t *coredev = client->coredev;
732
733
switch (smscore_get_device_mode(coredev)) {
734
case DEVICE_MODE_DVBT:
735
case DEVICE_MODE_DVBT_BDA:
736
return smsdvb_dvbt_set_frontend(fe, fep);
737
case DEVICE_MODE_ISDBT:
738
case DEVICE_MODE_ISDBT_BDA:
739
return smsdvb_isdbt_set_frontend(fe, fep);
740
default:
741
return -EINVAL;
742
}
743
}
744
745
static int smsdvb_get_frontend(struct dvb_frontend *fe,
746
struct dvb_frontend_parameters *fep)
747
{
748
struct smsdvb_client_t *client =
749
container_of(fe, struct smsdvb_client_t, frontend);
750
751
sms_debug("");
752
753
/* todo: */
754
memcpy(fep, &client->fe_params,
755
sizeof(struct dvb_frontend_parameters));
756
757
return 0;
758
}
759
760
static int smsdvb_init(struct dvb_frontend *fe)
761
{
762
struct smsdvb_client_t *client =
763
container_of(fe, struct smsdvb_client_t, frontend);
764
765
sms_board_power(client->coredev, 1);
766
767
sms_board_dvb3_event(client, DVB3_EVENT_INIT);
768
return 0;
769
}
770
771
static int smsdvb_sleep(struct dvb_frontend *fe)
772
{
773
struct smsdvb_client_t *client =
774
container_of(fe, struct smsdvb_client_t, frontend);
775
776
sms_board_led_feedback(client->coredev, SMS_LED_OFF);
777
sms_board_power(client->coredev, 0);
778
779
sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
780
781
return 0;
782
}
783
784
static void smsdvb_release(struct dvb_frontend *fe)
785
{
786
/* do nothing */
787
}
788
789
static struct dvb_frontend_ops smsdvb_fe_ops = {
790
.info = {
791
.name = "Siano Mobile Digital MDTV Receiver",
792
.type = FE_OFDM,
793
.frequency_min = 44250000,
794
.frequency_max = 867250000,
795
.frequency_stepsize = 250000,
796
.caps = FE_CAN_INVERSION_AUTO |
797
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
798
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
799
FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
800
FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
801
FE_CAN_GUARD_INTERVAL_AUTO |
802
FE_CAN_RECOVER |
803
FE_CAN_HIERARCHY_AUTO,
804
},
805
806
.release = smsdvb_release,
807
808
.set_frontend = smsdvb_set_frontend,
809
.get_frontend = smsdvb_get_frontend,
810
.get_tune_settings = smsdvb_get_tune_settings,
811
812
.read_status = smsdvb_read_status,
813
.read_ber = smsdvb_read_ber,
814
.read_signal_strength = smsdvb_read_signal_strength,
815
.read_snr = smsdvb_read_snr,
816
.read_ucblocks = smsdvb_read_ucblocks,
817
818
.init = smsdvb_init,
819
.sleep = smsdvb_sleep,
820
};
821
822
static int smsdvb_hotplug(struct smscore_device_t *coredev,
823
struct device *device, int arrival)
824
{
825
struct smsclient_params_t params;
826
struct smsdvb_client_t *client;
827
int rc;
828
829
/* device removal handled by onremove callback */
830
if (!arrival)
831
return 0;
832
client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
833
if (!client) {
834
sms_err("kmalloc() failed");
835
return -ENOMEM;
836
}
837
838
/* register dvb adapter */
839
rc = dvb_register_adapter(&client->adapter,
840
sms_get_board(
841
smscore_get_board_id(coredev))->name,
842
THIS_MODULE, device, adapter_nr);
843
if (rc < 0) {
844
sms_err("dvb_register_adapter() failed %d", rc);
845
goto adapter_error;
846
}
847
848
/* init dvb demux */
849
client->demux.dmx.capabilities = DMX_TS_FILTERING;
850
client->demux.filternum = 32; /* todo: nova ??? */
851
client->demux.feednum = 32;
852
client->demux.start_feed = smsdvb_start_feed;
853
client->demux.stop_feed = smsdvb_stop_feed;
854
855
rc = dvb_dmx_init(&client->demux);
856
if (rc < 0) {
857
sms_err("dvb_dmx_init failed %d", rc);
858
goto dvbdmx_error;
859
}
860
861
/* init dmxdev */
862
client->dmxdev.filternum = 32;
863
client->dmxdev.demux = &client->demux.dmx;
864
client->dmxdev.capabilities = 0;
865
866
rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
867
if (rc < 0) {
868
sms_err("dvb_dmxdev_init failed %d", rc);
869
goto dmxdev_error;
870
}
871
872
/* init and register frontend */
873
memcpy(&client->frontend.ops, &smsdvb_fe_ops,
874
sizeof(struct dvb_frontend_ops));
875
876
rc = dvb_register_frontend(&client->adapter, &client->frontend);
877
if (rc < 0) {
878
sms_err("frontend registration failed %d", rc);
879
goto frontend_error;
880
}
881
882
params.initial_id = 1;
883
params.data_type = MSG_SMS_DVBT_BDA_DATA;
884
params.onresponse_handler = smsdvb_onresponse;
885
params.onremove_handler = smsdvb_onremove;
886
params.context = client;
887
888
rc = smscore_register_client(coredev, &params, &client->smsclient);
889
if (rc < 0) {
890
sms_err("smscore_register_client() failed %d", rc);
891
goto client_error;
892
}
893
894
client->coredev = coredev;
895
896
init_completion(&client->tune_done);
897
898
kmutex_lock(&g_smsdvb_clientslock);
899
900
list_add(&client->entry, &g_smsdvb_clients);
901
902
kmutex_unlock(&g_smsdvb_clientslock);
903
904
client->event_fe_state = -1;
905
client->event_unc_state = -1;
906
sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
907
908
sms_info("success");
909
sms_board_setup(coredev);
910
911
return 0;
912
913
client_error:
914
dvb_unregister_frontend(&client->frontend);
915
916
frontend_error:
917
dvb_dmxdev_release(&client->dmxdev);
918
919
dmxdev_error:
920
dvb_dmx_release(&client->demux);
921
922
dvbdmx_error:
923
dvb_unregister_adapter(&client->adapter);
924
925
adapter_error:
926
kfree(client);
927
return rc;
928
}
929
930
static int __init smsdvb_module_init(void)
931
{
932
int rc;
933
934
INIT_LIST_HEAD(&g_smsdvb_clients);
935
kmutex_init(&g_smsdvb_clientslock);
936
937
rc = smscore_register_hotplug(smsdvb_hotplug);
938
939
sms_debug("");
940
941
return rc;
942
}
943
944
static void __exit smsdvb_module_exit(void)
945
{
946
smscore_unregister_hotplug(smsdvb_hotplug);
947
948
kmutex_lock(&g_smsdvb_clientslock);
949
950
while (!list_empty(&g_smsdvb_clients))
951
smsdvb_unregister_client(
952
(struct smsdvb_client_t *) g_smsdvb_clients.next);
953
954
kmutex_unlock(&g_smsdvb_clientslock);
955
}
956
957
module_init(smsdvb_module_init);
958
module_exit(smsdvb_module_exit);
959
960
MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
961
MODULE_AUTHOR("Siano Mobile Silicon, Inc. ([email protected])");
962
MODULE_LICENSE("GPL");
963
964