2 * Driver for the Siano SMS10xx USB dongle
4 * author: Anatoly Greenblat
6 * Copyright (c), 2005-2008 Siano Mobile Silicon, Inc.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 3 as
10 * published by the Free Software Foundation;
12 * Software distributed under the License is distributed on an "AS IS"
13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
15 * See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <linux/module.h>
23 #include <linux/init.h>
25 #include "smscoreapi.h"
27 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr
);
29 struct list_head g_smsdvb_clients
;
30 kmutex_t g_smsdvb_clientslock
;
32 int smsdvb_onresponse(void *context
, smscore_buffer_t
*cb
)
34 smsdvb_client_t
*client
= (smsdvb_client_t
*) context
;
35 SmsMsgHdr_ST
*phdr
= (SmsMsgHdr_ST
*)(((u8
*) cb
->p
) + cb
->offset
);
39 case MSG_SMS_DVBT_BDA_DATA
:
40 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1), cb
->size
- sizeof(SmsMsgHdr_ST
));
43 case MSG_SMS_RF_TUNE_RES
:
44 complete(&client
->tune_done
);
47 case MSG_SMS_GET_STATISTICS_RES
:
49 SmsMsgStatisticsInfo_ST
* p
= (SmsMsgStatisticsInfo_ST
*)(phdr
+ 1);
51 if (p
->Stat
.IsDemodLocked
)
53 client
->fe_status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_VITERBI
| FE_HAS_SYNC
| FE_HAS_LOCK
;
54 client
->fe_snr
= p
->Stat
.SNR
;
55 client
->fe_ber
= p
->Stat
.BER
;
57 if (p
->Stat
.InBandPwr
< -95)
58 client
->fe_signal_strength
= 0;
59 else if (p
->Stat
.InBandPwr
> -29)
60 client
->fe_signal_strength
= 100;
62 client
->fe_signal_strength
= (p
->Stat
.InBandPwr
+ 95) * 3 / 2;
66 client
->fe_status
= 0;
69 client
->fe_signal_strength
= 0;
72 complete(&client
->stat_done
);
77 smscore_putbuffer(client
->coredev
, cb
);
82 void smsdvb_unregister_client(smsdvb_client_t
* client
)
84 // must be called under clientslock
86 list_del(&client
->entry
);
88 smscore_unregister_client(client
->smsclient
);
89 dvb_unregister_frontend(&client
->frontend
);
90 dvb_dmxdev_release(&client
->dmxdev
);
91 dvb_dmx_release(&client
->demux
);
92 dvb_unregister_adapter(&client
->adapter
);
96 void smsdvb_onremove(void *context
)
98 kmutex_lock(&g_smsdvb_clientslock
);
100 smsdvb_unregister_client((smsdvb_client_t
*) context
);
102 kmutex_unlock(&g_smsdvb_clientslock
);
105 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
107 smsdvb_client_t
*client
= container_of(feed
->demux
, smsdvb_client_t
, demux
);
108 SmsMsgData_ST PidMsg
;
110 printk("%s add pid %d(%x)\n", __FUNCTION__
, feed
->pid
, feed
->pid
);
112 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
113 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
114 PidMsg
.xMsgHeader
.msgFlags
= 0;
115 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
116 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
117 PidMsg
.msgData
[0] = feed
->pid
;
119 return smsclient_sendrequest(client
->smsclient
, &PidMsg
, sizeof(PidMsg
));
122 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
124 smsdvb_client_t
*client
= container_of(feed
->demux
, smsdvb_client_t
, demux
);
125 SmsMsgData_ST PidMsg
;
127 printk("%s remove pid %d(%x)\n", __FUNCTION__
, feed
->pid
, feed
->pid
);
129 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
130 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
131 PidMsg
.xMsgHeader
.msgFlags
= 0;
132 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
133 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
134 PidMsg
.msgData
[0] = feed
->pid
;
136 return smsclient_sendrequest(client
->smsclient
, &PidMsg
, sizeof(PidMsg
));
139 static int smsdvb_sendrequest_and_wait(smsdvb_client_t
*client
, void* buffer
, size_t size
, struct completion
*completion
)
141 int rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
145 return wait_for_completion_timeout(completion
, msecs_to_jiffies(2000)) ? 0 : -ETIME
;
148 static int smsdvb_send_statistics_request(smsdvb_client_t
*client
)
150 SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
, DVBT_BDA_CONTROL_MSG_ID
, HIF_TASK
, sizeof(SmsMsgHdr_ST
), 0 };
151 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
), &client
->stat_done
);
154 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
156 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
157 int rc
= smsdvb_send_statistics_request(client
);
160 *stat
= client
->fe_status
;
165 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
167 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
168 int rc
= smsdvb_send_statistics_request(client
);
171 *ber
= client
->fe_ber
;
176 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
178 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
179 int rc
= smsdvb_send_statistics_request(client
);
182 *strength
= client
->fe_signal_strength
;
187 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
189 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
190 int rc
= smsdvb_send_statistics_request(client
);
193 *snr
= client
->fe_snr
;
198 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
, struct dvb_frontend_tune_settings
*tune
)
200 printk("%s\n", __FUNCTION__
);
202 tune
->min_delay_ms
= 400;
203 tune
->step_size
= 250000;
208 static int smsdvb_set_frontend(struct dvb_frontend
*fe
, struct dvb_frontend_parameters
*fep
)
210 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
218 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
219 Msg
.Msg
.msgDstId
= HIF_TASK
;
220 Msg
.Msg
.msgFlags
= 0;
221 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
222 Msg
.Msg
.msgLength
= sizeof(Msg
);
223 Msg
.Data
[0] = fep
->frequency
;
224 Msg
.Data
[2] = 12000000;
226 printk("%s freq %d band %d\n", __FUNCTION__
, fep
->frequency
, fep
->u
.ofdm
.bandwidth
);
228 switch(fep
->u
.ofdm
.bandwidth
)
230 case BANDWIDTH_8_MHZ
: Msg
.Data
[1] = BW_8_MHZ
; break;
231 case BANDWIDTH_7_MHZ
: Msg
.Data
[1] = BW_7_MHZ
; break;
232 case BANDWIDTH_6_MHZ
: Msg
.Data
[1] = BW_6_MHZ
; break;
233 // case BANDWIDTH_5_MHZ: Msg.Data[1] = BW_5_MHZ; break;
234 case BANDWIDTH_AUTO
: return -EOPNOTSUPP
;
235 default: return -EINVAL
;
238 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
), &client
->tune_done
);
241 static int smsdvb_get_frontend(struct dvb_frontend
*fe
, struct dvb_frontend_parameters
*fep
)
243 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
245 printk("%s\n", __FUNCTION__
);
248 memcpy(fep
, &client
->fe_params
, sizeof(struct dvb_frontend_parameters
));
252 static void smsdvb_release(struct dvb_frontend
*fe
)
257 static struct dvb_frontend_ops smsdvb_fe_ops
= {
259 .name
= "Siano Mobile Digital SMS10xx",
261 .frequency_min
= 44250000,
262 .frequency_max
= 867250000,
263 .frequency_stepsize
= 250000,
264 .caps
= FE_CAN_INVERSION_AUTO
|
265 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
266 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
267 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
| FE_CAN_QAM_AUTO
|
268 FE_CAN_TRANSMISSION_MODE_AUTO
|
269 FE_CAN_GUARD_INTERVAL_AUTO
|
271 FE_CAN_HIERARCHY_AUTO
,
274 .release
= smsdvb_release
,
276 .set_frontend
= smsdvb_set_frontend
,
277 .get_frontend
= smsdvb_get_frontend
,
278 .get_tune_settings
= smsdvb_get_tune_settings
,
280 .read_status
= smsdvb_read_status
,
281 .read_ber
= smsdvb_read_ber
,
282 .read_signal_strength
= smsdvb_read_signal_strength
,
283 .read_snr
= smsdvb_read_snr
,
286 int smsdvb_hotplug(smscore_device_t
*coredev
, struct device
* device
, int arrival
)
288 smsclient_params_t params
;
289 smsdvb_client_t
* client
;
292 // device removal handled by onremove callback
296 if (smscore_get_device_mode(coredev
) != 4)
298 rc
= smscore_set_device_mode(coredev
, 4);
303 client
= kzalloc(sizeof(smsdvb_client_t
), GFP_KERNEL
);
306 printk(KERN_INFO
"%s kmalloc() failed\n", __FUNCTION__
);
310 // register dvb adapter
311 rc
= dvb_register_adapter(&client
->adapter
, "Siano Digital Receiver", THIS_MODULE
, device
, adapter_nr
);
314 printk("%s dvb_register_adapter() failed %d\n", __func__
, rc
);
319 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
320 client
->demux
.filternum
= 32; // todo: nova ???
321 client
->demux
.feednum
= 32;
322 client
->demux
.start_feed
= smsdvb_start_feed
;
323 client
->demux
.stop_feed
= smsdvb_stop_feed
;
325 rc
= dvb_dmx_init(&client
->demux
);
328 printk("%s dvb_dmx_init failed %d\n\n", __FUNCTION__
, rc
);
333 client
->dmxdev
.filternum
= 32;
334 client
->dmxdev
.demux
= &client
->demux
.dmx
;
335 client
->dmxdev
.capabilities
= 0;
337 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
340 printk("%s dvb_dmxdev_init failed %d\n", __FUNCTION__
, rc
);
344 // init and register frontend
345 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
, sizeof(struct dvb_frontend_ops
));
347 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
350 printk("%s frontend registration failed %d\n", __FUNCTION__
, rc
);
354 params
.initial_id
= 0;
355 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
356 params
.onresponse_handler
= smsdvb_onresponse
;
357 params
.onremove_handler
= smsdvb_onremove
;
358 params
.context
= client
;
360 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
363 printk(KERN_INFO
"%s smscore_register_client() failed %d\n", __FUNCTION__
, rc
);
367 client
->coredev
= coredev
;
369 init_completion(&client
->tune_done
);
370 init_completion(&client
->stat_done
);
372 kmutex_lock(&g_smsdvb_clientslock
);
374 list_add(&client
->entry
, &g_smsdvb_clients
);
376 kmutex_unlock(&g_smsdvb_clientslock
);
378 printk(KERN_INFO
"%s success\n", __FUNCTION__
);
383 dvb_unregister_frontend(&client
->frontend
);
386 dvb_dmxdev_release(&client
->dmxdev
);
389 dvb_dmx_release(&client
->demux
);
392 dvb_unregister_adapter(&client
->adapter
);
399 int smsdvb_register(void)
403 INIT_LIST_HEAD(&g_smsdvb_clients
);
404 kmutex_init(&g_smsdvb_clientslock
);
406 rc
= smscore_register_hotplug(smsdvb_hotplug
);
408 printk(KERN_INFO
"%s\n", __FUNCTION__
);
413 void smsdvb_unregister(void)
415 smscore_unregister_hotplug(smsdvb_hotplug
);
417 kmutex_lock(&g_smsdvb_clientslock
);
419 while (!list_empty(&g_smsdvb_clients
))
420 smsdvb_unregister_client((smsdvb_client_t
*) g_smsdvb_clients
.next
);
422 kmutex_unlock(&g_smsdvb_clientslock
);