blob: 57f3560514abc307d3c2b476b00643cabb17a2fa [file] [log] [blame]
Uri Shkolnike5275792009-04-27 09:09:47 -03001/****************************************************************
2
3Siano Mobile Silicon, Inc.
4MDTV receiver kernel modules.
5Copyright (C) 2006-2008, Uri Shkolnik
6
7This program is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the 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,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20****************************************************************/
Steven Toth8d4f9d02008-05-22 18:05:26 -030021
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030022#include <linux/module.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030024#include <linux/init.h>
25
Uri Shkolnikc9679e32009-05-14 16:28:17 -030026#include "dmxdev.h"
27#include "dvbdev.h"
28#include "dvb_demux.h"
29#include "dvb_frontend.h"
30
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030031#include "smscoreapi.h"
Uri Shkolnikba79bb22009-05-12 11:37:09 -030032#include "smsendian.h"
Michael Krufky1c11d542008-06-18 22:09:55 -030033#include "sms-cards.h"
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030034
Michael Krufky9c59f9682008-05-19 18:57:12 -030035DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36
Michael Krufky62c71672008-08-31 17:15:47 -030037struct 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;
Michael Krufky62c71672008-08-31 17:15:47 -030049
Uri Shkolnik793786d2009-05-12 12:28:46 -030050 struct completion tune_done;
Michael Krufky62c71672008-08-31 17:15:47 -030051
Uri Shkolnik793786d2009-05-12 12:28:46 -030052 struct SMSHOSTLIB_STATISTICS_DVB_S sms_stat_dvb;
53 int event_fe_state;
54 int event_unc_state;
Michael Krufky62c71672008-08-31 17:15:47 -030055};
56
Adrian Bunkc5e0bd12008-07-21 23:17:36 -030057static struct list_head g_smsdvb_clients;
58static struct mutex g_smsdvb_clientslock;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -030059
Michael Krufky0d02efe2009-02-27 02:42:16 -030060static int sms_dbg;
61module_param_named(debug, sms_dbg, int, 0644);
62MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
63
Uri Shkolnik793786d2009-05-12 12:28:46 -030064/* Events that may come from DVB v3 adapter */
65static void sms_board_dvb3_event(struct smsdvb_client_t *client,
66 enum SMS_DVB3_EVENTS event) {
Uri Shkolnik4db989f2009-05-19 12:28:02 -030067
68 struct smscore_device_t *coredev = client->coredev;
69 switch (event) {
70 case DVB3_EVENT_INIT:
71 sms_debug("DVB3_EVENT_INIT");
72 sms_board_event(coredev, BOARD_EVENT_BIND);
73 break;
74 case DVB3_EVENT_SLEEP:
75 sms_debug("DVB3_EVENT_SLEEP");
76 sms_board_event(coredev, BOARD_EVENT_POWER_SUSPEND);
77 break;
78 case DVB3_EVENT_HOTPLUG:
79 sms_debug("DVB3_EVENT_HOTPLUG");
80 sms_board_event(coredev, BOARD_EVENT_POWER_INIT);
81 break;
82 case DVB3_EVENT_FE_LOCK:
83 if (client->event_fe_state != DVB3_EVENT_FE_LOCK) {
84 client->event_fe_state = DVB3_EVENT_FE_LOCK;
85 sms_debug("DVB3_EVENT_FE_LOCK");
86 sms_board_event(coredev, BOARD_EVENT_FE_LOCK);
87 }
88 break;
89 case DVB3_EVENT_FE_UNLOCK:
90 if (client->event_fe_state != DVB3_EVENT_FE_UNLOCK) {
91 client->event_fe_state = DVB3_EVENT_FE_UNLOCK;
92 sms_debug("DVB3_EVENT_FE_UNLOCK");
93 sms_board_event(coredev, BOARD_EVENT_FE_UNLOCK);
94 }
95 break;
96 case DVB3_EVENT_UNC_OK:
97 if (client->event_unc_state != DVB3_EVENT_UNC_OK) {
98 client->event_unc_state = DVB3_EVENT_UNC_OK;
99 sms_debug("DVB3_EVENT_UNC_OK");
100 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_OK);
101 }
102 break;
103 case DVB3_EVENT_UNC_ERR:
104 if (client->event_unc_state != DVB3_EVENT_UNC_ERR) {
105 client->event_unc_state = DVB3_EVENT_UNC_ERR;
106 sms_debug("DVB3_EVENT_UNC_ERR");
107 sms_board_event(coredev, BOARD_EVENT_MULTIPLEX_ERRORS);
108 }
109 break;
110
111 default:
112 sms_err("Unknown dvb3 api event");
113 break;
114 }
Uri Shkolnik793786d2009-05-12 12:28:46 -0300115}
116
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300117
118static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
119 struct SMSHOSTLIB_STATISTICS_ST *p)
120{
121 if (sms_dbg & 2) {
122 printk(KERN_DEBUG "Reserved = %d", p->Reserved);
123 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
124 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
125 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
126 printk(KERN_DEBUG "SNR = %d", p->SNR);
127 printk(KERN_DEBUG "BER = %d", p->BER);
128 printk(KERN_DEBUG "FIB_CRC = %d", p->FIB_CRC);
129 printk(KERN_DEBUG "TS_PER = %d", p->TS_PER);
130 printk(KERN_DEBUG "MFER = %d", p->MFER);
131 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
132 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
133 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
134 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
135 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
136 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
137 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
138 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
139 printk(KERN_DEBUG "CodeRate = %d", p->CodeRate);
140 printk(KERN_DEBUG "LPCodeRate = %d", p->LPCodeRate);
141 printk(KERN_DEBUG "Hierarchy = %d", p->Hierarchy);
142 printk(KERN_DEBUG "Constellation = %d", p->Constellation);
143 printk(KERN_DEBUG "BurstSize = %d", p->BurstSize);
144 printk(KERN_DEBUG "BurstDuration = %d", p->BurstDuration);
145 printk(KERN_DEBUG "BurstCycleTime = %d", p->BurstCycleTime);
146 printk(KERN_DEBUG "CalculatedBurstCycleTime = %d", p->CalculatedBurstCycleTime);
147 printk(KERN_DEBUG "NumOfRows = %d", p->NumOfRows);
148 printk(KERN_DEBUG "NumOfPaddCols = %d", p->NumOfPaddCols);
149 printk(KERN_DEBUG "NumOfPunctCols = %d", p->NumOfPunctCols);
150 printk(KERN_DEBUG "ErrorTSPackets = %d", p->ErrorTSPackets);
151 printk(KERN_DEBUG "TotalTSPackets = %d", p->TotalTSPackets);
152 printk(KERN_DEBUG "NumOfValidMpeTlbs = %d", p->NumOfValidMpeTlbs);
153 printk(KERN_DEBUG "NumOfInvalidMpeTlbs = %d", p->NumOfInvalidMpeTlbs);
154 printk(KERN_DEBUG "NumOfCorrectedMpeTlbs = %d", p->NumOfCorrectedMpeTlbs);
155 printk(KERN_DEBUG "BERErrorCount = %d", p->BERErrorCount);
156 printk(KERN_DEBUG "BERBitCount = %d", p->BERBitCount);
157 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
158 printk(KERN_DEBUG "PreBER = %d", p->PreBER);
159 printk(KERN_DEBUG "CellId = %d", p->CellId);
160 printk(KERN_DEBUG "DvbhSrvIndHP = %d", p->DvbhSrvIndHP);
161 printk(KERN_DEBUG "DvbhSrvIndLP = %d", p->DvbhSrvIndLP);
162 printk(KERN_DEBUG "NumMPEReceived = %d", p->NumMPEReceived);
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300163 }
164
165 pReceptionData->IsDemodLocked = p->IsDemodLocked;
166
167 pReceptionData->SNR = p->SNR;
168 pReceptionData->BER = p->BER;
169 pReceptionData->BERErrorCount = p->BERErrorCount;
170 pReceptionData->InBandPwr = p->InBandPwr;
171 pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
172};
173
174
175static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_S *pReceptionData,
176 struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
177{
178 int i;
179
180 if (sms_dbg & 2) {
181 printk(KERN_DEBUG "IsRfLocked = %d", p->IsRfLocked);
182 printk(KERN_DEBUG "IsDemodLocked = %d", p->IsDemodLocked);
183 printk(KERN_DEBUG "IsExternalLNAOn = %d", p->IsExternalLNAOn);
184 printk(KERN_DEBUG "SNR = %d", p->SNR);
185 printk(KERN_DEBUG "RSSI = %d", p->RSSI);
186 printk(KERN_DEBUG "InBandPwr = %d", p->InBandPwr);
187 printk(KERN_DEBUG "CarrierOffset = %d", p->CarrierOffset);
188 printk(KERN_DEBUG "Frequency = %d", p->Frequency);
189 printk(KERN_DEBUG "Bandwidth = %d", p->Bandwidth);
190 printk(KERN_DEBUG "TransmissionMode = %d", p->TransmissionMode);
191 printk(KERN_DEBUG "ModemState = %d", p->ModemState);
192 printk(KERN_DEBUG "GuardInterval = %d", p->GuardInterval);
193 printk(KERN_DEBUG "SystemType = %d", p->SystemType);
194 printk(KERN_DEBUG "PartialReception = %d", p->PartialReception);
195 printk(KERN_DEBUG "NumOfLayers = %d", p->NumOfLayers);
196 printk(KERN_DEBUG "SmsToHostTxErrors = %d", p->SmsToHostTxErrors);
197
198 for (i = 0; i < 3; i++) {
199 printk(KERN_DEBUG "%d: CodeRate = %d", i, p->LayerInfo[i].CodeRate);
200 printk(KERN_DEBUG "%d: Constellation = %d", i, p->LayerInfo[i].Constellation);
201 printk(KERN_DEBUG "%d: BER = %d", i, p->LayerInfo[i].BER);
202 printk(KERN_DEBUG "%d: BERErrorCount = %d", i, p->LayerInfo[i].BERErrorCount);
203 printk(KERN_DEBUG "%d: BERBitCount = %d", i, p->LayerInfo[i].BERBitCount);
204 printk(KERN_DEBUG "%d: PreBER = %d", i, p->LayerInfo[i].PreBER);
205 printk(KERN_DEBUG "%d: TS_PER = %d", i, p->LayerInfo[i].TS_PER);
206 printk(KERN_DEBUG "%d: ErrorTSPackets = %d", i, p->LayerInfo[i].ErrorTSPackets);
207 printk(KERN_DEBUG "%d: TotalTSPackets = %d", i, p->LayerInfo[i].TotalTSPackets);
208 printk(KERN_DEBUG "%d: TILdepthI = %d", i, p->LayerInfo[i].TILdepthI);
209 printk(KERN_DEBUG "%d: NumberOfSegments = %d", i, p->LayerInfo[i].NumberOfSegments);
210 printk(KERN_DEBUG "%d: TMCCErrors = %d", i, p->LayerInfo[i].TMCCErrors);
211 }
212 }
213
214 pReceptionData->IsDemodLocked = p->IsDemodLocked;
215
216 pReceptionData->SNR = p->SNR;
217 pReceptionData->InBandPwr = p->InBandPwr;
218
219 pReceptionData->ErrorTSPackets = 0;
220 pReceptionData->BER = 0;
221 pReceptionData->BERErrorCount = 0;
222 for (i = 0; i < 3; i++) {
223 pReceptionData->BER += p->LayerInfo[i].BER;
224 pReceptionData->BERErrorCount += p->LayerInfo[i].BERErrorCount;
225 pReceptionData->ErrorTSPackets += p->LayerInfo[i].ErrorTSPackets;
226 }
227}
228
Michael Krufky0c071f32008-06-21 02:44:02 -0300229static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300230{
Michael Krufky18245e12008-06-15 17:52:24 -0300231 struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300232 struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
233 + cb->offset);
234 u32 *pMsgData = (u32 *) phdr + 1;
235 /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
236 bool is_status_update = false;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300237
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300238 smsendian_handle_rx_message((struct SmsMsgData_ST *) phdr);
239
Michael Krufkyfa830e82008-06-15 15:52:43 -0300240 switch (phdr->msgType) {
Michael Krufky82237412008-06-15 15:14:13 -0300241 case MSG_SMS_DVBT_BDA_DATA:
242 dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
Michael Krufky18245e12008-06-15 17:52:24 -0300243 cb->size - sizeof(struct SmsMsgHdr_ST));
Michael Krufky82237412008-06-15 15:14:13 -0300244 break;
245
246 case MSG_SMS_RF_TUNE_RES:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300247 case MSG_SMS_ISDBT_TUNE_RES:
Michael Krufky82237412008-06-15 15:14:13 -0300248 complete(&client->tune_done);
249 break;
250
Uri Shkolnik793786d2009-05-12 12:28:46 -0300251 case MSG_SMS_SIGNAL_DETECTED_IND:
Uri Shkolnik793786d2009-05-12 12:28:46 -0300252 client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
253 is_status_update = true;
254 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300255
Uri Shkolnik793786d2009-05-12 12:28:46 -0300256 case MSG_SMS_NO_SIGNAL_IND:
Uri Shkolnik793786d2009-05-12 12:28:46 -0300257 client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
258 is_status_update = true;
259 break;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300260
Uri Shkolnik793786d2009-05-12 12:28:46 -0300261 case MSG_SMS_TRANSMISSION_IND: {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300262 pMsgData++;
263 memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
264 sizeof(struct TRANSMISSION_STATISTICS_S));
265
266 /* Mo need to correct guard interval
267 * (as opposed to old statistics message).
268 */
269 CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
270 CORRECT_STAT_TRANSMISSON_MODE(
271 client->sms_stat_dvb.TransmissionData);
272 is_status_update = true;
273 break;
274 }
275 case MSG_SMS_HO_PER_SLICES_IND: {
276 struct RECEPTION_STATISTICS_S *pReceptionData =
277 &client->sms_stat_dvb.ReceptionData;
278 struct SRVM_SIGNAL_STATUS_S SignalStatusData;
279
Uri Shkolnik793786d2009-05-12 12:28:46 -0300280 pMsgData++;
281 SignalStatusData.result = pMsgData[0];
282 SignalStatusData.snr = pMsgData[1];
283 SignalStatusData.inBandPower = (s32) pMsgData[2];
284 SignalStatusData.tsPackets = pMsgData[3];
285 SignalStatusData.etsPackets = pMsgData[4];
286 SignalStatusData.constellation = pMsgData[5];
287 SignalStatusData.hpCode = pMsgData[6];
288 SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
289 SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
290 SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
291 SignalStatusData.reason = pMsgData[10];
292 SignalStatusData.requestId = pMsgData[11];
293 pReceptionData->IsRfLocked = pMsgData[16];
294 pReceptionData->IsDemodLocked = pMsgData[17];
295 pReceptionData->ModemState = pMsgData[12];
296 pReceptionData->SNR = pMsgData[1];
297 pReceptionData->BER = pMsgData[13];
298 pReceptionData->RSSI = pMsgData[14];
299 CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
300
301 pReceptionData->InBandPwr = (s32) pMsgData[2];
302 pReceptionData->CarrierOffset = (s32) pMsgData[15];
303 pReceptionData->TotalTSPackets = pMsgData[3];
304 pReceptionData->ErrorTSPackets = pMsgData[4];
305
306 /* TS PER */
307 if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
308 > 0) {
309 pReceptionData->TS_PER = (SignalStatusData.etsPackets
310 * 100) / (SignalStatusData.tsPackets
311 + SignalStatusData.etsPackets);
Michael Krufky82237412008-06-15 15:14:13 -0300312 } else {
Uri Shkolnik793786d2009-05-12 12:28:46 -0300313 pReceptionData->TS_PER = 0;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300314 }
Michael Krufky82237412008-06-15 15:14:13 -0300315
Uri Shkolnik793786d2009-05-12 12:28:46 -0300316 pReceptionData->BERBitCount = pMsgData[18];
317 pReceptionData->BERErrorCount = pMsgData[19];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300318
Uri Shkolnik793786d2009-05-12 12:28:46 -0300319 pReceptionData->MRC_SNR = pMsgData[20];
320 pReceptionData->MRC_InBandPwr = pMsgData[21];
321 pReceptionData->MRC_RSSI = pMsgData[22];
322
323 is_status_update = true;
324 break;
325 }
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300326 case MSG_SMS_GET_STATISTICS_RES: {
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300327 union {
328 struct SMSHOSTLIB_STATISTICS_ISDBT_ST isdbt;
329 struct SmsMsgStatisticsInfo_ST dvb;
330 } *p = (void *) (phdr + 1);
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300331 struct RECEPTION_STATISTICS_S *pReceptionData =
332 &client->sms_stat_dvb.ReceptionData;
333
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300334 is_status_update = true;
Mauro Carvalho Chehab5eb23972009-12-25 11:29:42 -0300335
336 switch (smscore_get_device_mode(client->coredev)) {
337 case DEVICE_MODE_ISDBT:
338 case DEVICE_MODE_ISDBT_BDA:
339 smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
340 break;
341 default:
342 smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
343 }
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300344 if (!pReceptionData->IsDemodLocked) {
345 pReceptionData->SNR = 0;
346 pReceptionData->BER = 0;
347 pReceptionData->BERErrorCount = 0;
348 pReceptionData->InBandPwr = 0;
349 pReceptionData->ErrorTSPackets = 0;
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300350 }
351
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300352 complete(&client->tune_done);
353 break;
354 }
355 default:
Mauro Carvalho Chehab4c3bdb52013-03-09 09:27:39 -0300356 sms_info("message not handled");
Uri Shkolnik793786d2009-05-12 12:28:46 -0300357 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300358 smscore_putbuffer(client->coredev, cb);
359
Uri Shkolnik793786d2009-05-12 12:28:46 -0300360 if (is_status_update) {
361 if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
362 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
363 | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
364 sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
365 if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
366 == 0)
367 sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
368 else
369 sms_board_dvb3_event(client,
370 DVB3_EVENT_UNC_ERR);
371
372 } else {
Mauro Carvalho Chehabb4622c12009-12-25 18:04:17 -0300373 if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
374 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
375 else
376 client->fe_status = 0;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300377 sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
378 }
379 }
380
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300381 return 0;
382}
383
Michael Krufky0c071f32008-06-21 02:44:02 -0300384static void smsdvb_unregister_client(struct smsdvb_client_t *client)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300385{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300386 /* must be called under clientslock */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300387
388 list_del(&client->entry);
389
390 smscore_unregister_client(client->smsclient);
391 dvb_unregister_frontend(&client->frontend);
392 dvb_dmxdev_release(&client->dmxdev);
393 dvb_dmx_release(&client->demux);
394 dvb_unregister_adapter(&client->adapter);
395 kfree(client);
396}
397
Michael Krufky0c071f32008-06-21 02:44:02 -0300398static void smsdvb_onremove(void *context)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300399{
400 kmutex_lock(&g_smsdvb_clientslock);
401
Michael Krufky18245e12008-06-15 17:52:24 -0300402 smsdvb_unregister_client((struct smsdvb_client_t *) context);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300403
404 kmutex_unlock(&g_smsdvb_clientslock);
405}
406
407static int smsdvb_start_feed(struct dvb_demux_feed *feed)
408{
Michael Krufky18245e12008-06-15 17:52:24 -0300409 struct smsdvb_client_t *client =
410 container_of(feed->demux, struct smsdvb_client_t, demux);
411 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300412
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300413 sms_debug("add pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300414 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300415
416 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
417 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
418 PidMsg.xMsgHeader.msgFlags = 0;
419 PidMsg.xMsgHeader.msgType = MSG_SMS_ADD_PID_FILTER_REQ;
420 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
421 PidMsg.msgData[0] = feed->pid;
422
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300423 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
Michael Krufky82237412008-06-15 15:14:13 -0300424 return smsclient_sendrequest(client->smsclient,
425 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300426}
427
428static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
429{
Michael Krufky18245e12008-06-15 17:52:24 -0300430 struct smsdvb_client_t *client =
431 container_of(feed->demux, struct smsdvb_client_t, demux);
432 struct SmsMsgData_ST PidMsg;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300433
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300434 sms_debug("remove pid %d(%x)",
Michael Krufky068d6c02008-06-19 01:15:46 -0300435 feed->pid, feed->pid);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300436
437 PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
438 PidMsg.xMsgHeader.msgDstId = HIF_TASK;
439 PidMsg.xMsgHeader.msgFlags = 0;
440 PidMsg.xMsgHeader.msgType = MSG_SMS_REMOVE_PID_FILTER_REQ;
441 PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
442 PidMsg.msgData[0] = feed->pid;
443
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300444 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)&PidMsg);
Michael Krufky82237412008-06-15 15:14:13 -0300445 return smsclient_sendrequest(client->smsclient,
446 &PidMsg, sizeof(PidMsg));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300447}
448
Michael Krufky18245e12008-06-15 17:52:24 -0300449static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t *client,
Michael Krufkya83ccdd2008-05-06 03:11:51 -0300450 void *buffer, size_t size,
451 struct completion *completion)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300452{
Uri Shkolnikba79bb22009-05-12 11:37:09 -0300453 int rc;
454
455 smsendian_handle_tx_message((struct SmsMsgHdr_ST *)buffer);
456 rc = smsclient_sendrequest(client->smsclient, buffer, size);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300457 if (rc < 0)
458 return rc;
459
Michael Krufky82237412008-06-15 15:14:13 -0300460 return wait_for_completion_timeout(completion,
461 msecs_to_jiffies(2000)) ?
462 0 : -ETIME;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300463}
464
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300465static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
466{
467 int rc;
468 struct SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ,
469 DVBT_BDA_CONTROL_MSG_ID,
470 HIF_TASK,
471 sizeof(struct SmsMsgHdr_ST), 0 };
472
473 rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
474 &client->tune_done);
475
476 return rc;
477}
478
Michael Krufky3746b612009-07-12 23:30:14 -0300479static inline int led_feedback(struct smsdvb_client_t *client)
480{
481 if (client->fe_status & FE_HAS_LOCK)
482 return sms_board_led_feedback(client->coredev,
483 (client->sms_stat_dvb.ReceptionData.BER
484 == 0) ? SMS_LED_HI : SMS_LED_LO);
485 else
486 return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
487}
488
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300489static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
490{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300491 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300492 struct smsdvb_client_t *client;
493 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300494
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300495 rc = smsdvb_send_statistics_request(client);
496
Uri Shkolnik793786d2009-05-12 12:28:46 -0300497 *stat = client->fe_status;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300498
Michael Krufky3746b612009-07-12 23:30:14 -0300499 led_feedback(client);
500
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300501 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300502}
503
504static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
505{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300506 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300507 struct smsdvb_client_t *client;
508 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300509
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300510 rc = smsdvb_send_statistics_request(client);
511
Uri Shkolnik793786d2009-05-12 12:28:46 -0300512 *ber = client->sms_stat_dvb.ReceptionData.BER;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300513
Michael Krufky3746b612009-07-12 23:30:14 -0300514 led_feedback(client);
515
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300516 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300517}
518
519static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
520{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300521 int rc;
522
Uri Shkolnik793786d2009-05-12 12:28:46 -0300523 struct smsdvb_client_t *client;
524 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300525
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300526 rc = smsdvb_send_statistics_request(client);
527
Uri Shkolnik793786d2009-05-12 12:28:46 -0300528 if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
529 *strength = 0;
530 else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
531 *strength = 100;
532 else
533 *strength =
534 (client->sms_stat_dvb.ReceptionData.InBandPwr
535 + 95) * 3 / 2;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300536
Michael Krufky3746b612009-07-12 23:30:14 -0300537 led_feedback(client);
538
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300539 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300540}
541
542static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
543{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300544 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300545 struct smsdvb_client_t *client;
546 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300547
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300548 rc = smsdvb_send_statistics_request(client);
549
Uri Shkolnik793786d2009-05-12 12:28:46 -0300550 *snr = client->sms_stat_dvb.ReceptionData.SNR;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300551
Michael Krufky3746b612009-07-12 23:30:14 -0300552 led_feedback(client);
553
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300554 return rc;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300555}
556
Michael Krufky851a9092008-11-22 14:56:37 -0300557static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
558{
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300559 int rc;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300560 struct smsdvb_client_t *client;
561 client = container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky851a9092008-11-22 14:56:37 -0300562
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300563 rc = smsdvb_send_statistics_request(client);
564
Uri Shkolnik793786d2009-05-12 12:28:46 -0300565 *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
Michael Krufky851a9092008-11-22 14:56:37 -0300566
Michael Krufky3746b612009-07-12 23:30:14 -0300567 led_feedback(client);
568
Mauro Carvalho Chehab67ae1d22009-12-23 10:07:16 -0300569 return rc;
Michael Krufky851a9092008-11-22 14:56:37 -0300570}
571
Michael Krufky82237412008-06-15 15:14:13 -0300572static int smsdvb_get_tune_settings(struct dvb_frontend *fe,
573 struct dvb_frontend_tune_settings *tune)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300574{
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300575 sms_debug("");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300576
577 tune->min_delay_ms = 400;
578 tune->step_size = 250000;
579 tune->max_drift = 0;
580 return 0;
581}
582
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300583static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300584{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300585 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300586 struct smsdvb_client_t *client =
587 container_of(fe, struct smsdvb_client_t, frontend);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300588
Michael Krufky18245e12008-06-15 17:52:24 -0300589 struct {
590 struct SmsMsgHdr_ST Msg;
Michael Krufky82237412008-06-15 15:14:13 -0300591 u32 Data[3];
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300592 } Msg;
593
Michael Krufky3746b612009-07-12 23:30:14 -0300594 int ret;
595
Uri Shkolnik793786d2009-05-12 12:28:46 -0300596 client->fe_status = FE_HAS_SIGNAL;
597 client->event_fe_state = -1;
598 client->event_unc_state = -1;
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300599 fe->dtv_property_cache.delivery_system = SYS_DVBT;
Uri Shkolnik793786d2009-05-12 12:28:46 -0300600
601 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
602 Msg.Msg.msgDstId = HIF_TASK;
603 Msg.Msg.msgFlags = 0;
604 Msg.Msg.msgType = MSG_SMS_RF_TUNE_REQ;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300605 Msg.Msg.msgLength = sizeof(Msg);
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300606 Msg.Data[0] = c->frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300607 Msg.Data[2] = 12000000;
608
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300609 sms_info("%s: freq %d band %d", __func__, c->frequency,
610 c->bandwidth_hz);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300611
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -0300612 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300613 case 8:
614 Msg.Data[1] = BW_8_MHZ;
615 break;
616 case 7:
617 Msg.Data[1] = BW_7_MHZ;
618 break;
619 case 6:
620 Msg.Data[1] = BW_6_MHZ;
621 break;
622 case 0:
623 return -EOPNOTSUPP;
624 default:
625 return -EINVAL;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300626 }
Michael Krufky3746b612009-07-12 23:30:14 -0300627 /* Disable LNA, if any. An error is returned if no LNA is present */
628 ret = sms_board_lna_control(client->coredev, 0);
629 if (ret == 0) {
630 fe_status_t status;
631
632 /* tune with LNA off at first */
633 ret = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
634 &client->tune_done);
635
636 smsdvb_read_status(fe, &status);
637
638 if (status & FE_HAS_LOCK)
639 return ret;
640
Lucas De Marchi25985ed2011-03-30 22:57:33 -0300641 /* previous tune didn't lock - enable LNA and tune again */
Michael Krufky3746b612009-07-12 23:30:14 -0300642 sms_board_lna_control(client->coredev, 1);
643 }
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300644
Michael Krufky82237412008-06-15 15:14:13 -0300645 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
646 &client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300647}
648
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300649static int smsdvb_isdbt_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300650{
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300651 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300652 struct smsdvb_client_t *client =
653 container_of(fe, struct smsdvb_client_t, frontend);
654
655 struct {
656 struct SmsMsgHdr_ST Msg;
657 u32 Data[4];
658 } Msg;
659
Mauro Carvalho Chehabe85c97a2009-12-25 07:17:03 -0300660 fe->dtv_property_cache.delivery_system = SYS_ISDBT;
661
Michael Krufky6b26fce2009-12-22 21:08:49 -0300662 Msg.Msg.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
663 Msg.Msg.msgDstId = HIF_TASK;
664 Msg.Msg.msgFlags = 0;
665 Msg.Msg.msgType = MSG_SMS_ISDBT_TUNE_REQ;
666 Msg.Msg.msgLength = sizeof(Msg);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300667
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300668 if (c->isdbt_sb_segment_idx == -1)
669 c->isdbt_sb_segment_idx = 0;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300670
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300671 switch (c->isdbt_sb_segment_count) {
672 case 3:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300673 Msg.Data[1] = BW_ISDBT_3SEG;
674 break;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300675 case 1:
Michael Krufky6b26fce2009-12-22 21:08:49 -0300676 Msg.Data[1] = BW_ISDBT_1SEG;
677 break;
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300678 case 0: /* AUTO */
Mauro Carvalho Chehab643e15a2009-12-25 07:29:06 -0300679 switch (c->bandwidth_hz / 1000000) {
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300680 case 8:
681 case 7:
682 c->isdbt_sb_segment_count = 3;
683 Msg.Data[1] = BW_ISDBT_3SEG;
684 break;
685 case 6:
686 c->isdbt_sb_segment_count = 1;
687 Msg.Data[1] = BW_ISDBT_1SEG;
688 break;
689 default: /* Assumes 6 MHZ bw */
690 c->isdbt_sb_segment_count = 1;
691 c->bandwidth_hz = 6000;
692 Msg.Data[1] = BW_ISDBT_1SEG;
693 break;
694 }
695 break;
Michael Krufky6b26fce2009-12-22 21:08:49 -0300696 default:
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300697 sms_info("Segment count %d not supported", c->isdbt_sb_segment_count);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300698 return -EINVAL;
699 }
700
Mauro Carvalho Chehabcf4fab72009-12-23 11:28:46 -0300701 Msg.Data[0] = c->frequency;
702 Msg.Data[2] = 12000000;
703 Msg.Data[3] = c->isdbt_sb_segment_idx;
704
705 sms_info("%s: freq %d segwidth %d segindex %d\n", __func__,
706 c->frequency, c->isdbt_sb_segment_count,
707 c->isdbt_sb_segment_idx);
708
Michael Krufky6b26fce2009-12-22 21:08:49 -0300709 return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
710 &client->tune_done);
711}
712
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300713static int smsdvb_set_frontend(struct dvb_frontend *fe)
Michael Krufky6b26fce2009-12-22 21:08:49 -0300714{
715 struct smsdvb_client_t *client =
716 container_of(fe, struct smsdvb_client_t, frontend);
717 struct smscore_device_t *coredev = client->coredev;
718
719 switch (smscore_get_device_mode(coredev)) {
720 case DEVICE_MODE_DVBT:
721 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300722 return smsdvb_dvbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300723 case DEVICE_MODE_ISDBT:
724 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300725 return smsdvb_isdbt_set_frontend(fe);
Michael Krufky6b26fce2009-12-22 21:08:49 -0300726 default:
727 return -EINVAL;
728 }
729}
730
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -0300731static int smsdvb_get_frontend(struct dvb_frontend *fe)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300732{
Mauro Carvalho Chehab7c61d802011-12-30 11:30:21 -0300733 struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
Michael Krufky18245e12008-06-15 17:52:24 -0300734 struct smsdvb_client_t *client =
735 container_of(fe, struct smsdvb_client_t, frontend);
Gianluca Gennarid1382102012-02-20 07:50:33 -0300736 struct smscore_device_t *coredev = client->coredev;
737 struct TRANSMISSION_STATISTICS_S *td =
738 &client->sms_stat_dvb.TransmissionData;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300739
Gianluca Gennarid1382102012-02-20 07:50:33 -0300740 switch (smscore_get_device_mode(coredev)) {
741 case DEVICE_MODE_DVBT:
742 case DEVICE_MODE_DVBT_BDA:
743 fep->frequency = td->Frequency;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300744
Gianluca Gennarid1382102012-02-20 07:50:33 -0300745 switch (td->Bandwidth) {
746 case 6:
747 fep->bandwidth_hz = 6000000;
748 break;
749 case 7:
750 fep->bandwidth_hz = 7000000;
751 break;
752 case 8:
753 fep->bandwidth_hz = 8000000;
754 break;
755 }
756
757 switch (td->TransmissionMode) {
758 case 2:
759 fep->transmission_mode = TRANSMISSION_MODE_2K;
760 break;
761 case 8:
762 fep->transmission_mode = TRANSMISSION_MODE_8K;
763 }
764
765 switch (td->GuardInterval) {
766 case 0:
767 fep->guard_interval = GUARD_INTERVAL_1_32;
768 break;
769 case 1:
770 fep->guard_interval = GUARD_INTERVAL_1_16;
771 break;
772 case 2:
773 fep->guard_interval = GUARD_INTERVAL_1_8;
774 break;
775 case 3:
776 fep->guard_interval = GUARD_INTERVAL_1_4;
777 break;
778 }
779
780 switch (td->CodeRate) {
781 case 0:
782 fep->code_rate_HP = FEC_1_2;
783 break;
784 case 1:
785 fep->code_rate_HP = FEC_2_3;
786 break;
787 case 2:
788 fep->code_rate_HP = FEC_3_4;
789 break;
790 case 3:
791 fep->code_rate_HP = FEC_5_6;
792 break;
793 case 4:
794 fep->code_rate_HP = FEC_7_8;
795 break;
796 }
797
798 switch (td->LPCodeRate) {
799 case 0:
800 fep->code_rate_LP = FEC_1_2;
801 break;
802 case 1:
803 fep->code_rate_LP = FEC_2_3;
804 break;
805 case 2:
806 fep->code_rate_LP = FEC_3_4;
807 break;
808 case 3:
809 fep->code_rate_LP = FEC_5_6;
810 break;
811 case 4:
812 fep->code_rate_LP = FEC_7_8;
813 break;
814 }
815
816 switch (td->Constellation) {
817 case 0:
818 fep->modulation = QPSK;
819 break;
820 case 1:
821 fep->modulation = QAM_16;
822 break;
823 case 2:
824 fep->modulation = QAM_64;
825 break;
826 }
827
828 switch (td->Hierarchy) {
829 case 0:
830 fep->hierarchy = HIERARCHY_NONE;
831 break;
832 case 1:
833 fep->hierarchy = HIERARCHY_1;
834 break;
835 case 2:
836 fep->hierarchy = HIERARCHY_2;
837 break;
838 case 3:
839 fep->hierarchy = HIERARCHY_4;
840 break;
841 }
842
843 fep->inversion = INVERSION_AUTO;
844 break;
845 case DEVICE_MODE_ISDBT:
846 case DEVICE_MODE_ISDBT_BDA:
847 fep->frequency = td->Frequency;
848 fep->bandwidth_hz = 6000000;
849 /* todo: retrive the other parameters */
850 break;
851 default:
852 return -EINVAL;
853 }
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300854
855 return 0;
856}
857
858static int smsdvb_init(struct dvb_frontend *fe)
859{
860 struct smsdvb_client_t *client =
861 container_of(fe, struct smsdvb_client_t, frontend);
862
Michael Krufky3746b612009-07-12 23:30:14 -0300863 sms_board_power(client->coredev, 1);
864
Uri Shkolnik793786d2009-05-12 12:28:46 -0300865 sms_board_dvb3_event(client, DVB3_EVENT_INIT);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300866 return 0;
867}
868
869static int smsdvb_sleep(struct dvb_frontend *fe)
870{
871 struct smsdvb_client_t *client =
872 container_of(fe, struct smsdvb_client_t, frontend);
873
Michael Krufky3746b612009-07-12 23:30:14 -0300874 sms_board_led_feedback(client->coredev, SMS_LED_OFF);
875 sms_board_power(client->coredev, 0);
876
Uri Shkolnik793786d2009-05-12 12:28:46 -0300877 sms_board_dvb3_event(client, DVB3_EVENT_SLEEP);
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300878
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300879 return 0;
880}
881
882static void smsdvb_release(struct dvb_frontend *fe)
883{
Michael Krufkyfa830e82008-06-15 15:52:43 -0300884 /* do nothing */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300885}
886
887static struct dvb_frontend_ops smsdvb_fe_ops = {
888 .info = {
Uri Shkolnike0f14c22008-08-31 00:44:04 -0300889 .name = "Siano Mobile Digital MDTV Receiver",
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300890 .frequency_min = 44250000,
891 .frequency_max = 867250000,
892 .frequency_stepsize = 250000,
893 .caps = FE_CAN_INVERSION_AUTO |
Michael Krufky82237412008-06-15 15:14:13 -0300894 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
895 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
896 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
897 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
898 FE_CAN_GUARD_INTERVAL_AUTO |
899 FE_CAN_RECOVER |
900 FE_CAN_HIERARCHY_AUTO,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300901 },
902
903 .release = smsdvb_release,
904
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300905 .set_frontend = smsdvb_set_frontend,
906 .get_frontend = smsdvb_get_frontend,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300907 .get_tune_settings = smsdvb_get_tune_settings,
908
909 .read_status = smsdvb_read_status,
910 .read_ber = smsdvb_read_ber,
911 .read_signal_strength = smsdvb_read_signal_strength,
912 .read_snr = smsdvb_read_snr,
Michael Krufky851a9092008-11-22 14:56:37 -0300913 .read_ucblocks = smsdvb_read_ucblocks,
Michael Krufky7a6fbed2008-11-22 14:26:37 -0300914
915 .init = smsdvb_init,
916 .sleep = smsdvb_sleep,
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300917};
918
Michael Krufky0c071f32008-06-21 02:44:02 -0300919static int smsdvb_hotplug(struct smscore_device_t *coredev,
920 struct device *device, int arrival)
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300921{
Michael Krufky18245e12008-06-15 17:52:24 -0300922 struct smsclient_params_t params;
923 struct smsdvb_client_t *client;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300924 int rc;
925
Michael Krufkyfa830e82008-06-15 15:52:43 -0300926 /* device removal handled by onremove callback */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300927 if (!arrival)
928 return 0;
Michael Krufky18245e12008-06-15 17:52:24 -0300929 client = kzalloc(sizeof(struct smsdvb_client_t), GFP_KERNEL);
Michael Krufky82237412008-06-15 15:14:13 -0300930 if (!client) {
Michael Krufkyeb250942008-06-19 22:07:23 -0300931 sms_err("kmalloc() failed");
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300932 return -ENOMEM;
933 }
934
Michael Krufkyfa830e82008-06-15 15:52:43 -0300935 /* register dvb adapter */
Michael Krufky1c11d542008-06-18 22:09:55 -0300936 rc = dvb_register_adapter(&client->adapter,
937 sms_get_board(
938 smscore_get_board_id(coredev))->name,
Michael Krufky82237412008-06-15 15:14:13 -0300939 THIS_MODULE, device, adapter_nr);
940 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300941 sms_err("dvb_register_adapter() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300942 goto adapter_error;
943 }
944
Michael Krufkyfa830e82008-06-15 15:52:43 -0300945 /* init dvb demux */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300946 client->demux.dmx.capabilities = DMX_TS_FILTERING;
Michael Krufkyfa830e82008-06-15 15:52:43 -0300947 client->demux.filternum = 32; /* todo: nova ??? */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300948 client->demux.feednum = 32;
949 client->demux.start_feed = smsdvb_start_feed;
950 client->demux.stop_feed = smsdvb_stop_feed;
951
952 rc = dvb_dmx_init(&client->demux);
Michael Krufky82237412008-06-15 15:14:13 -0300953 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300954 sms_err("dvb_dmx_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300955 goto dvbdmx_error;
956 }
957
Michael Krufkyfa830e82008-06-15 15:52:43 -0300958 /* init dmxdev */
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300959 client->dmxdev.filternum = 32;
960 client->dmxdev.demux = &client->demux.dmx;
961 client->dmxdev.capabilities = 0;
962
963 rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
Michael Krufky82237412008-06-15 15:14:13 -0300964 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300965 sms_err("dvb_dmxdev_init failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300966 goto dmxdev_error;
967 }
968
Michael Krufkyfa830e82008-06-15 15:52:43 -0300969 /* init and register frontend */
Michael Krufky82237412008-06-15 15:14:13 -0300970 memcpy(&client->frontend.ops, &smsdvb_fe_ops,
971 sizeof(struct dvb_frontend_ops));
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300972
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300973 switch (smscore_get_device_mode(coredev)) {
974 case DEVICE_MODE_DVBT:
975 case DEVICE_MODE_DVBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -0300976 client->frontend.ops.delsys[0] = SYS_DVBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300977 break;
978 case DEVICE_MODE_ISDBT:
979 case DEVICE_MODE_ISDBT_BDA:
Mauro Carvalho Chehab9bd58e72012-03-01 07:25:39 -0300980 client->frontend.ops.delsys[0] = SYS_ISDBT;
Mauro Carvalho Chehab15115c12011-12-26 16:31:29 -0300981 break;
982 }
983
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300984 rc = dvb_register_frontend(&client->adapter, &client->frontend);
Michael Krufky82237412008-06-15 15:14:13 -0300985 if (rc < 0) {
Michael Krufkya0c0abc2008-06-19 20:35:21 -0300986 sms_err("frontend registration failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300987 goto frontend_error;
988 }
989
Michael Krufkyf17407a2008-06-14 00:43:26 -0300990 params.initial_id = 1;
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300991 params.data_type = MSG_SMS_DVBT_BDA_DATA;
992 params.onresponse_handler = smsdvb_onresponse;
993 params.onremove_handler = smsdvb_onremove;
994 params.context = client;
995
996 rc = smscore_register_client(coredev, &params, &client->smsclient);
Michael Krufky82237412008-06-15 15:14:13 -0300997 if (rc < 0) {
Michael Krufkyeb250942008-06-19 22:07:23 -0300998 sms_err("smscore_register_client() failed %d", rc);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -0300999 goto client_error;
1000 }
1001
1002 client->coredev = coredev;
1003
1004 init_completion(&client->tune_done);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001005
1006 kmutex_lock(&g_smsdvb_clientslock);
1007
1008 list_add(&client->entry, &g_smsdvb_clients);
1009
1010 kmutex_unlock(&g_smsdvb_clientslock);
1011
Uri Shkolnik793786d2009-05-12 12:28:46 -03001012 client->event_fe_state = -1;
1013 client->event_unc_state = -1;
1014 sms_board_dvb3_event(client, DVB3_EVENT_HOTPLUG);
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001015
Uri Shkolnik793786d2009-05-12 12:28:46 -03001016 sms_info("success");
Michael Krufky250fa672008-11-16 22:45:42 -03001017 sms_board_setup(coredev);
1018
Michael Krufky2e5c1ec82008-05-19 18:56:13 -03001019 return 0;
1020
1021client_error:
1022 dvb_unregister_frontend(&client->frontend);
1023
1024frontend_error:
1025 dvb_dmxdev_release(&client->dmxdev);
1026
1027dmxdev_error:
1028 dvb_dmx_release(&client->demux);
1029
1030dvbdmx_error:
1031 dvb_unregister_adapter(&client->adapter);
1032
1033adapter_error:
1034 kfree(client);
1035 return rc;
1036}
1037
Márton Németh2184dda2009-12-11 20:05:10 -03001038static int __init smsdvb_module_init(void)
Steven Totheae55662008-05-22 18:04:36 -03001039{
1040 int rc;
1041
1042 INIT_LIST_HEAD(&g_smsdvb_clients);
1043 kmutex_init(&g_smsdvb_clientslock);
1044
1045 rc = smscore_register_hotplug(smsdvb_hotplug);
1046
Michael Krufkya0c0abc2008-06-19 20:35:21 -03001047 sms_debug("");
Steven Totheae55662008-05-22 18:04:36 -03001048
1049 return rc;
1050}
1051
Márton Németh2184dda2009-12-11 20:05:10 -03001052static void __exit smsdvb_module_exit(void)
Steven Totheae55662008-05-22 18:04:36 -03001053{
1054 smscore_unregister_hotplug(smsdvb_hotplug);
1055
1056 kmutex_lock(&g_smsdvb_clientslock);
1057
1058 while (!list_empty(&g_smsdvb_clients))
Michael Krufky82237412008-06-15 15:14:13 -03001059 smsdvb_unregister_client(
Michael Krufky18245e12008-06-15 17:52:24 -03001060 (struct smsdvb_client_t *) g_smsdvb_clients.next);
Steven Totheae55662008-05-22 18:04:36 -03001061
1062 kmutex_unlock(&g_smsdvb_clientslock);
Steven Totheae55662008-05-22 18:04:36 -03001063}
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001064
1065module_init(smsdvb_module_init);
1066module_exit(smsdvb_module_exit);
1067
1068MODULE_DESCRIPTION("SMS DVB subsystem adaptation module");
Uri Shkolnik843d0602009-05-12 13:13:13 -03001069MODULE_AUTHOR("Siano Mobile Silicon, Inc. (uris@siano-ms.com)");
Uri Shkolnike0f14c22008-08-31 00:44:04 -03001070MODULE_LICENSE("GPL");