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
, struct smscore_buffer_t
*cb
)
34 struct smsdvb_client_t
*client
= (struct smsdvb_client_t
*) context
;
35 struct SmsMsgHdr_ST
*phdr
=
36 (struct SmsMsgHdr_ST
*)(((u8
*) cb
->p
) + cb
->offset
);
38 switch (phdr
->msgType
) {
39 case MSG_SMS_DVBT_BDA_DATA
:
40 dvb_dmx_swfilter(&client
->demux
, (u8
*)(phdr
+ 1),
41 cb
->size
- sizeof(struct SmsMsgHdr_ST
));
44 case MSG_SMS_RF_TUNE_RES
:
45 complete(&client
->tune_done
);
48 case MSG_SMS_GET_STATISTICS_RES
:
50 struct SmsMsgStatisticsInfo_ST
*p
=
51 (struct SmsMsgStatisticsInfo_ST
*)(phdr
+ 1);
53 if (p
->Stat
.IsDemodLocked
) {
54 client
->fe_status
= FE_HAS_SIGNAL
|
60 client
->fe_snr
= p
->Stat
.SNR
;
61 client
->fe_ber
= p
->Stat
.BER
;
63 if (p
->Stat
.InBandPwr
< -95)
64 client
->fe_signal_strength
= 0;
65 else if (p
->Stat
.InBandPwr
> -29)
66 client
->fe_signal_strength
= 100;
68 client
->fe_signal_strength
=
69 (p
->Stat
.InBandPwr
+ 95) * 3 / 2;
71 client
->fe_status
= 0;
74 client
->fe_signal_strength
= 0;
77 complete(&client
->stat_done
);
81 smscore_putbuffer(client
->coredev
, cb
);
86 void smsdvb_unregister_client(struct smsdvb_client_t
*client
)
88 /* must be called under clientslock */
90 list_del(&client
->entry
);
92 smscore_unregister_client(client
->smsclient
);
93 dvb_unregister_frontend(&client
->frontend
);
94 dvb_dmxdev_release(&client
->dmxdev
);
95 dvb_dmx_release(&client
->demux
);
96 dvb_unregister_adapter(&client
->adapter
);
100 void smsdvb_onremove(void *context
)
102 kmutex_lock(&g_smsdvb_clientslock
);
104 smsdvb_unregister_client((struct smsdvb_client_t
*) context
);
106 kmutex_unlock(&g_smsdvb_clientslock
);
109 static int smsdvb_start_feed(struct dvb_demux_feed
*feed
)
111 struct smsdvb_client_t
*client
=
112 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
113 struct SmsMsgData_ST PidMsg
;
115 printk(KERN_DEBUG
"%s add pid %d(%x)\n", __func__
,
116 feed
->pid
, feed
->pid
);
118 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
119 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
120 PidMsg
.xMsgHeader
.msgFlags
= 0;
121 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_ADD_PID_FILTER_REQ
;
122 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
123 PidMsg
.msgData
[0] = feed
->pid
;
125 return smsclient_sendrequest(client
->smsclient
,
126 &PidMsg
, sizeof(PidMsg
));
129 static int smsdvb_stop_feed(struct dvb_demux_feed
*feed
)
131 struct smsdvb_client_t
*client
=
132 container_of(feed
->demux
, struct smsdvb_client_t
, demux
);
133 struct SmsMsgData_ST PidMsg
;
135 printk(KERN_DEBUG
"%s remove pid %d(%x)\n", __func__
,
136 feed
->pid
, feed
->pid
);
138 PidMsg
.xMsgHeader
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
139 PidMsg
.xMsgHeader
.msgDstId
= HIF_TASK
;
140 PidMsg
.xMsgHeader
.msgFlags
= 0;
141 PidMsg
.xMsgHeader
.msgType
= MSG_SMS_REMOVE_PID_FILTER_REQ
;
142 PidMsg
.xMsgHeader
.msgLength
= sizeof(PidMsg
);
143 PidMsg
.msgData
[0] = feed
->pid
;
145 return smsclient_sendrequest(client
->smsclient
,
146 &PidMsg
, sizeof(PidMsg
));
149 static int smsdvb_sendrequest_and_wait(struct smsdvb_client_t
*client
,
150 void *buffer
, size_t size
,
151 struct completion
*completion
)
153 int rc
= smsclient_sendrequest(client
->smsclient
, buffer
, size
);
157 return wait_for_completion_timeout(completion
,
158 msecs_to_jiffies(2000)) ?
162 static int smsdvb_send_statistics_request(struct smsdvb_client_t
*client
)
164 struct SmsMsgHdr_ST Msg
= { MSG_SMS_GET_STATISTICS_REQ
,
165 DVBT_BDA_CONTROL_MSG_ID
,
166 HIF_TASK
, sizeof(struct SmsMsgHdr_ST
), 0 };
167 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
171 static int smsdvb_read_status(struct dvb_frontend
*fe
, fe_status_t
*stat
)
173 struct smsdvb_client_t
*client
=
174 container_of(fe
, struct smsdvb_client_t
, frontend
);
175 int rc
= smsdvb_send_statistics_request(client
);
178 *stat
= client
->fe_status
;
183 static int smsdvb_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
185 struct smsdvb_client_t
*client
=
186 container_of(fe
, struct smsdvb_client_t
, frontend
);
187 int rc
= smsdvb_send_statistics_request(client
);
190 *ber
= client
->fe_ber
;
195 static int smsdvb_read_signal_strength(struct dvb_frontend
*fe
, u16
*strength
)
197 struct smsdvb_client_t
*client
=
198 container_of(fe
, struct smsdvb_client_t
, frontend
);
199 int rc
= smsdvb_send_statistics_request(client
);
202 *strength
= client
->fe_signal_strength
;
207 static int smsdvb_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
209 struct smsdvb_client_t
*client
=
210 container_of(fe
, struct smsdvb_client_t
, frontend
);
211 int rc
= smsdvb_send_statistics_request(client
);
214 *snr
= client
->fe_snr
;
219 static int smsdvb_get_tune_settings(struct dvb_frontend
*fe
,
220 struct dvb_frontend_tune_settings
*tune
)
222 printk(KERN_DEBUG
"%s\n", __func__
);
224 tune
->min_delay_ms
= 400;
225 tune
->step_size
= 250000;
230 static int smsdvb_set_frontend(struct dvb_frontend
*fe
,
231 struct dvb_frontend_parameters
*fep
)
233 struct smsdvb_client_t
*client
=
234 container_of(fe
, struct smsdvb_client_t
, frontend
);
237 struct SmsMsgHdr_ST Msg
;
241 Msg
.Msg
.msgSrcId
= DVBT_BDA_CONTROL_MSG_ID
;
242 Msg
.Msg
.msgDstId
= HIF_TASK
;
243 Msg
.Msg
.msgFlags
= 0;
244 Msg
.Msg
.msgType
= MSG_SMS_RF_TUNE_REQ
;
245 Msg
.Msg
.msgLength
= sizeof(Msg
);
246 Msg
.Data
[0] = fep
->frequency
;
247 Msg
.Data
[2] = 12000000;
249 printk(KERN_DEBUG
"%s freq %d band %d\n", __func__
,
250 fep
->frequency
, fep
->u
.ofdm
.bandwidth
);
252 switch (fep
->u
.ofdm
.bandwidth
) {
253 case BANDWIDTH_8_MHZ
: Msg
.Data
[1] = BW_8_MHZ
; break;
254 case BANDWIDTH_7_MHZ
: Msg
.Data
[1] = BW_7_MHZ
; break;
255 case BANDWIDTH_6_MHZ
: Msg
.Data
[1] = BW_6_MHZ
; break;
256 case BANDWIDTH_AUTO
: return -EOPNOTSUPP
;
257 default: return -EINVAL
;
260 return smsdvb_sendrequest_and_wait(client
, &Msg
, sizeof(Msg
),
264 static int smsdvb_get_frontend(struct dvb_frontend
*fe
,
265 struct dvb_frontend_parameters
*fep
)
267 struct smsdvb_client_t
*client
=
268 container_of(fe
, struct smsdvb_client_t
, frontend
);
270 printk(KERN_DEBUG
"%s\n", __func__
);
273 memcpy(fep
, &client
->fe_params
,
274 sizeof(struct dvb_frontend_parameters
));
278 static void smsdvb_release(struct dvb_frontend
*fe
)
283 static struct dvb_frontend_ops smsdvb_fe_ops
= {
285 .name
= "Siano Mobile Digital SMS10xx",
287 .frequency_min
= 44250000,
288 .frequency_max
= 867250000,
289 .frequency_stepsize
= 250000,
290 .caps
= FE_CAN_INVERSION_AUTO
|
291 FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
|
292 FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
|
293 FE_CAN_QPSK
| FE_CAN_QAM_16
| FE_CAN_QAM_64
|
294 FE_CAN_QAM_AUTO
| FE_CAN_TRANSMISSION_MODE_AUTO
|
295 FE_CAN_GUARD_INTERVAL_AUTO
|
297 FE_CAN_HIERARCHY_AUTO
,
300 .release
= smsdvb_release
,
302 .set_frontend
= smsdvb_set_frontend
,
303 .get_frontend
= smsdvb_get_frontend
,
304 .get_tune_settings
= smsdvb_get_tune_settings
,
306 .read_status
= smsdvb_read_status
,
307 .read_ber
= smsdvb_read_ber
,
308 .read_signal_strength
= smsdvb_read_signal_strength
,
309 .read_snr
= smsdvb_read_snr
,
312 int smsdvb_hotplug(struct smscore_device_t
*coredev
,
313 struct device
*device
, int arrival
)
315 struct smsclient_params_t params
;
316 struct smsdvb_client_t
*client
;
319 /* device removal handled by onremove callback */
323 if (smscore_get_device_mode(coredev
) != 4) {
324 printk(KERN_ERR
"%sSMS Device mode is not set for "
325 "DVB operation.\n", __func__
);
329 client
= kzalloc(sizeof(struct smsdvb_client_t
), GFP_KERNEL
);
331 printk(KERN_INFO
"%s kmalloc() failed\n", __func__
);
335 /* register dvb adapter */
336 rc
= dvb_register_adapter(&client
->adapter
, "Siano Digital Receiver",
337 THIS_MODULE
, device
, adapter_nr
);
339 printk(KERN_ERR
"%s dvb_register_adapter() failed %d\n",
345 client
->demux
.dmx
.capabilities
= DMX_TS_FILTERING
;
346 client
->demux
.filternum
= 32; /* todo: nova ??? */
347 client
->demux
.feednum
= 32;
348 client
->demux
.start_feed
= smsdvb_start_feed
;
349 client
->demux
.stop_feed
= smsdvb_stop_feed
;
351 rc
= dvb_dmx_init(&client
->demux
);
353 printk(KERN_ERR
"%s dvb_dmx_init failed %d\n\n",
359 client
->dmxdev
.filternum
= 32;
360 client
->dmxdev
.demux
= &client
->demux
.dmx
;
361 client
->dmxdev
.capabilities
= 0;
363 rc
= dvb_dmxdev_init(&client
->dmxdev
, &client
->adapter
);
365 printk(KERN_ERR
"%s dvb_dmxdev_init failed %d\n",
370 /* init and register frontend */
371 memcpy(&client
->frontend
.ops
, &smsdvb_fe_ops
,
372 sizeof(struct dvb_frontend_ops
));
374 rc
= dvb_register_frontend(&client
->adapter
, &client
->frontend
);
376 printk(KERN_ERR
"%s frontend registration failed %d\n",
381 params
.initial_id
= 1;
382 params
.data_type
= MSG_SMS_DVBT_BDA_DATA
;
383 params
.onresponse_handler
= smsdvb_onresponse
;
384 params
.onremove_handler
= smsdvb_onremove
;
385 params
.context
= client
;
387 rc
= smscore_register_client(coredev
, ¶ms
, &client
->smsclient
);
389 printk(KERN_INFO
"%s smscore_register_client() failed %d\n",
394 client
->coredev
= coredev
;
396 init_completion(&client
->tune_done
);
397 init_completion(&client
->stat_done
);
399 kmutex_lock(&g_smsdvb_clientslock
);
401 list_add(&client
->entry
, &g_smsdvb_clients
);
403 kmutex_unlock(&g_smsdvb_clientslock
);
405 printk(KERN_INFO
"%s success\n", __func__
);
410 dvb_unregister_frontend(&client
->frontend
);
413 dvb_dmxdev_release(&client
->dmxdev
);
416 dvb_dmx_release(&client
->demux
);
419 dvb_unregister_adapter(&client
->adapter
);
426 int smsdvb_register(void)
430 INIT_LIST_HEAD(&g_smsdvb_clients
);
431 kmutex_init(&g_smsdvb_clientslock
);
433 rc
= smscore_register_hotplug(smsdvb_hotplug
);
435 printk(KERN_INFO
"%s\n", __func__
);
440 void smsdvb_unregister(void)
442 smscore_unregister_hotplug(smsdvb_hotplug
);
444 kmutex_lock(&g_smsdvb_clientslock
);
446 while (!list_empty(&g_smsdvb_clients
))
447 smsdvb_unregister_client(
448 (struct smsdvb_client_t
*) g_smsdvb_clients
.next
);
450 kmutex_unlock(&g_smsdvb_clientslock
);