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
);
37 switch (phdr
->msgType
) {
38 case MSG_SMS_DVBT_BDA_DATA
:
39 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
40 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
=
50 (SmsMsgStatisticsInfo_ST
*)(phdr
+ 1);
52 if (p
->Stat
.IsDemodLocked
) {
53 client
->fe_status
= FE_HAS_SIGNAL
|
59 client
->fe_snr
= p
->Stat
.SNR
;
60 client
->fe_ber
= p
->Stat
.BER
;
62 if (p
->Stat
.InBandPwr
< -95)
63 client
->fe_signal_strength
= 0;
64 else if (p
->Stat
.InBandPwr
> -29)
65 client
->fe_signal_strength
= 100;
67 client
->fe_signal_strength
=
68 (p
->Stat
.InBandPwr
+ 95) * 3 / 2;
70 client
->fe_status
= 0;
73 client
->fe_signal_strength
= 0;
76 complete(&client
->stat_done
);
80 smscore_putbuffer(client
->coredev
, cb
);
85 void smsdvb_unregister_client(smsdvb_client_t
*client
)
87 /* must be called under clientslock */
89 list_del(&client
->entry
);
91 smscore_unregister_client(client
->smsclient
);
92 dvb_unregister_frontend(&client
->frontend
);
93 dvb_dmxdev_release(&client
->dmxdev
);
94 dvb_dmx_release(&client
->demux
);
95 dvb_unregister_adapter(&client
->adapter
);
99 void smsdvb_onremove(void *context
)
101 kmutex_lock(&g_smsdvb_clientslock
);
103 smsdvb_unregister_client((smsdvb_client_t
*) context
);
105 kmutex_unlock(&g_smsdvb_clientslock
);
108 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
110 smsdvb_client_t
*client
=
111 container_of(feed
->demux
, smsdvb_client_t
, demux
);
112 SmsMsgData_ST PidMsg
;
114 printk("%s add pid %d(%x)\n", __func__
, feed
->pid
, feed
->pid
);
116 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
117 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
118 PidMsg
.xMsgHeader
.msgFlags
= 0;
119 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
120 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
121 PidMsg
.msgData
[0] = feed
->pid
;
123 return smsclient_sendrequest(client
->smsclient
,
124 &PidMsg
, sizeof(PidMsg
));
127 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
129 smsdvb_client_t
*client
=
130 container_of(feed
->demux
, smsdvb_client_t
, demux
);
131 SmsMsgData_ST PidMsg
;
133 printk("%s remove pid %d(%x)\n", __func__
, feed
->pid
, feed
->pid
);
135 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
136 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
137 PidMsg
.xMsgHeader
.msgFlags
= 0;
138 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
139 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
140 PidMsg
.msgData
[0] = feed
->pid
;
142 return smsclient_sendrequest(client
->smsclient
,
143 &PidMsg
, sizeof(PidMsg
));
146 static int smsdvb_sendrequest_and_wait(smsdvb_client_t
*client
,
147 void *buffer
, size_t size
,
148 struct completion
*completion
)
150 int rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
154 return wait_for_completion_timeout(completion
,
155 msecs_to_jiffies(2000)) ?
159 static int smsdvb_send_statistics_request(smsdvb_client_t
*client
)
161 SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
162 DVBT_BDA_CONTROL_MSG_ID
,
163 HIF_TASK
, sizeof(SmsMsgHdr_ST
), 0 };
164 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
168 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
170 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
171 int rc
= smsdvb_send_statistics_request(client
);
174 *stat
= client
->fe_status
;
179 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
181 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
182 int rc
= smsdvb_send_statistics_request(client
);
185 *ber
= client
->fe_ber
;
190 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
192 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
193 int rc
= smsdvb_send_statistics_request(client
);
196 *strength
= client
->fe_signal_strength
;
201 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
203 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
204 int rc
= smsdvb_send_statistics_request(client
);
207 *snr
= client
->fe_snr
;
212 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
213 struct dvb_frontend_tune_settings
*tune
)
215 printk("%s\n", __func__
);
217 tune
->min_delay_ms
= 400;
218 tune
->step_size
= 250000;
223 static int smsdvb_set_frontend(struct dvb_frontend
*fe
,
224 struct dvb_frontend_parameters
*fep
)
226 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
234 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
235 Msg
.Msg
.msgDstId
= HIF_TASK
;
236 Msg
.Msg
.msgFlags
= 0;
237 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
238 Msg
.Msg
.msgLength
= sizeof(Msg
);
239 Msg
.Data
[0] = fep
->frequency
;
240 Msg
.Data
[2] = 12000000;
242 printk("%s freq %d band %d\n", __func__
,
243 fep
->frequency
, fep
->u
.ofdm
.bandwidth
);
245 switch (fep
->u
.ofdm
.bandwidth
) {
246 case BANDWIDTH_8_MHZ
: Msg
.Data
[1] = BW_8_MHZ
; break;
247 case BANDWIDTH_7_MHZ
: Msg
.Data
[1] = BW_7_MHZ
; break;
248 case BANDWIDTH_6_MHZ
: Msg
.Data
[1] = BW_6_MHZ
; break;
249 case BANDWIDTH_AUTO
: return -EOPNOTSUPP
;
250 default: return -EINVAL
;
253 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
257 static int smsdvb_get_frontend(struct dvb_frontend
*fe
,
258 struct dvb_frontend_parameters
*fep
)
260 smsdvb_client_t
*client
= container_of(fe
, smsdvb_client_t
, frontend
);
262 printk("%s\n", __func__
);
265 memcpy(fep
, &client
->fe_params
,
266 sizeof(struct dvb_frontend_parameters
));
270 static void smsdvb_release(struct dvb_frontend
*fe
)
275 static struct dvb_frontend_ops smsdvb_fe_ops
= {
277 .name
= "Siano Mobile Digital SMS10xx",
279 .frequency_min
= 44250000,
280 .frequency_max
= 867250000,
281 .frequency_stepsize
= 250000,
282 .caps
= FE_CAN_INVERSION_AUTO
|
283 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
284 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
285 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
286 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
287 FE_CAN_GUARD_INTERVAL_AUTO
|
289 FE_CAN_HIERARCHY_AUTO
,
292 .release
= smsdvb_release
,
294 .set_frontend
= smsdvb_set_frontend
,
295 .get_frontend
= smsdvb_get_frontend
,
296 .get_tune_settings
= smsdvb_get_tune_settings
,
298 .read_status
= smsdvb_read_status
,
299 .read_ber
= smsdvb_read_ber
,
300 .read_signal_strength
= smsdvb_read_signal_strength
,
301 .read_snr
= smsdvb_read_snr
,
304 int smsdvb_hotplug(smscore_device_t
*coredev
,
305 struct device
*device
, int arrival
)
307 smsclient_params_t params
;
308 smsdvb_client_t
*client
;
311 /* device removal handled by onremove callback */
315 if (smscore_get_device_mode(coredev
) != 4) {
316 printk(KERN_ERR
"%sSMS Device mode is not set for DVB operation.\n", __func__
);
320 client
= kzalloc(sizeof(smsdvb_client_t
), GFP_KERNEL
);
322 printk(KERN_INFO
"%s kmalloc() failed\n", __func__
);
326 /* register dvb adapter */
327 rc
= dvb_register_adapter(&client
->adapter
, "Siano Digital Receiver",
328 THIS_MODULE
, device
, adapter_nr
);
330 printk("%s dvb_register_adapter() failed %d\n", __func__
, rc
);
335 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
336 client
->demux
.filternum
= 32; /* todo: nova ??? */
337 client
->demux
.feednum
= 32;
338 client
->demux
.start_feed
= smsdvb_start_feed
;
339 client
->demux
.stop_feed
= smsdvb_stop_feed
;
341 rc
= dvb_dmx_init(&client
->demux
);
343 printk("%s dvb_dmx_init failed %d\n\n", __func__
, rc
);
348 client
->dmxdev
.filternum
= 32;
349 client
->dmxdev
.demux
= &client
->demux
.dmx
;
350 client
->dmxdev
.capabilities
= 0;
352 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
354 printk("%s dvb_dmxdev_init failed %d\n", __func__
, rc
);
358 /* init and register frontend */
359 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
360 sizeof(struct dvb_frontend_ops
));
362 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
364 printk("%s frontend registration failed %d\n", __func__
, rc
);
368 params
.initial_id
= 1;
369 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
370 params
.onresponse_handler
= smsdvb_onresponse
;
371 params
.onremove_handler
= smsdvb_onremove
;
372 params
.context
= client
;
374 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
376 printk(KERN_INFO
"%s smscore_register_client() failed %d\n",
381 client
->coredev
= coredev
;
383 init_completion(&client
->tune_done
);
384 init_completion(&client
->stat_done
);
386 kmutex_lock(&g_smsdvb_clientslock
);
388 list_add(&client
->entry
, &g_smsdvb_clients
);
390 kmutex_unlock(&g_smsdvb_clientslock
);
392 printk(KERN_INFO
"%s success\n", __func__
);
397 dvb_unregister_frontend(&client
->frontend
);
400 dvb_dmxdev_release(&client
->dmxdev
);
403 dvb_dmx_release(&client
->demux
);
406 dvb_unregister_adapter(&client
->adapter
);
413 int smsdvb_register(void)
417 INIT_LIST_HEAD(&g_smsdvb_clients
);
418 kmutex_init(&g_smsdvb_clientslock
);
420 rc
= smscore_register_hotplug(smsdvb_hotplug
);
422 printk(KERN_INFO
"%s\n", __func__
);
427 void smsdvb_unregister(void)
429 smscore_unregister_hotplug(smsdvb_hotplug
);
431 kmutex_lock(&g_smsdvb_clientslock
);
433 while (!list_empty(&g_smsdvb_clients
))
434 smsdvb_unregister_client(
435 (smsdvb_client_t
*) g_smsdvb_clients
.next
);
437 kmutex_unlock(&g_smsdvb_clientslock
);