]> err.no Git - linux-2.6/blob - drivers/media/mdtv/smsdvb.c
V4L/DVB (8266): sms1xxx: merge modules
[linux-2.6] / drivers / media / mdtv / smsdvb.c
1 #include <linux/module.h>
2 #include <linux/init.h>
3
4 #include "smscoreapi.h"
5
6 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
7
8 struct list_head g_smsdvb_clients;
9 kmutex_t g_smsdvb_clientslock;
10
11 int smsdvb_onresponse(void *context, smscore_buffer_t *cb)
12 {
13         smsdvb_client_t *client = (smsdvb_client_t *) context;
14         SmsMsgHdr_ST *phdr = (SmsMsgHdr_ST *)(((u8*) cb->p) + cb->offset);
15
16         switch(phdr->msgType)
17         {
18                 case MSG_SMS_DVBT_BDA_DATA:
19                         dvb_dmx_swfilter(&client->demux, (u8*)(phdr + 1), cb->size - sizeof(SmsMsgHdr_ST));
20                         break;
21
22                 case MSG_SMS_RF_TUNE_RES:
23                         complete(&client->tune_done);
24                         break;
25
26                 case MSG_SMS_GET_STATISTICS_RES:
27                 {
28                         SmsMsgStatisticsInfo_ST* p = (SmsMsgStatisticsInfo_ST*)(phdr + 1);
29
30                         if (p->Stat.IsDemodLocked)
31                         {
32                                 client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
33                                 client->fe_snr = p->Stat.SNR;
34                                 client->fe_ber = p->Stat.BER;
35
36                                 if (p->Stat.InBandPwr < -95)
37                                         client->fe_signal_strength = 0;
38                                 else if (p->Stat.InBandPwr > -29)
39                                         client->fe_signal_strength = 100;
40                                 else
41                                         client->fe_signal_strength = (p->Stat.InBandPwr + 95) * 3 / 2;
42                         }
43                         else
44                         {
45                                 client->fe_status = 0;
46                                 client->fe_snr =
47                                 client->fe_ber =
48                                 client->fe_signal_strength = 0;
49                         }
50
51                         complete(&client->stat_done);
52                         break;
53                 }
54         }
55
56         smscore_putbuffer(client->coredev, cb);
57
58         return 0;
59 }
60
61 void smsdvb_unregister_client(smsdvb_client_t* client)
62 {
63         // must be called under clientslock
64
65         list_del(&client->entry);
66
67         smscore_unregister_client(client->smsclient);
68         dvb_unregister_frontend(&client->frontend);
69         dvb_dmxdev_release(&client->dmxdev);
70         dvb_dmx_release(&client->demux);
71         dvb_unregister_adapter(&client->adapter);
72         kfree(client);
73 }
74
75 void smsdvb_onremove(void *context)
76 {
77         kmutex_lock(&g_smsdvb_clientslock);
78
79         smsdvb_unregister_client((smsdvb_client_t*) context);
80
81         kmutex_unlock(&g_smsdvb_clientslock);
82 }
83
84 static int smsdvb_start_feed(struct dvb_demux_feed *feed)
85 {
86         smsdvb_client_t *client = container_of(feed->demux, smsdvb_client_t, demux);
87         SmsMsgData_ST PidMsg;
88
89         printk("%s add pid %d(%x)\n", __FUNCTION__, feed->pid, feed->pid);
90
91         PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
92         PidMsg.xMsgHeader.msgDstId = HIF_TASK;
93         PidMsg.xMsgHeader.msgFlags = 0;
94         PidMsg.xMsgHeader.msgType  = MSG_SMS_ADD_PID_FILTER_REQ;
95         PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
96         PidMsg.msgData[0] = feed->pid;
97
98         return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg));
99 }
100
101 static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
102 {
103         smsdvb_client_t *client = container_of(feed->demux, smsdvb_client_t, demux);
104         SmsMsgData_ST PidMsg;
105
106         printk("%s remove pid %d(%x)\n", __FUNCTION__, feed->pid, feed->pid);
107
108         PidMsg.xMsgHeader.msgSrcId = DVBT_BDA_CONTROL_MSG_ID;
109         PidMsg.xMsgHeader.msgDstId = HIF_TASK;
110         PidMsg.xMsgHeader.msgFlags = 0;
111         PidMsg.xMsgHeader.msgType  = MSG_SMS_REMOVE_PID_FILTER_REQ;
112         PidMsg.xMsgHeader.msgLength = sizeof(PidMsg);
113         PidMsg.msgData[0] = feed->pid;
114
115         return smsclient_sendrequest(client->smsclient, &PidMsg, sizeof(PidMsg));
116 }
117
118 static int smsdvb_sendrequest_and_wait(smsdvb_client_t *client, void* buffer, size_t size, struct completion *completion)
119 {
120         int rc = smsclient_sendrequest(client->smsclient, buffer, size);
121         if (rc < 0)
122                 return rc;
123
124         return wait_for_completion_timeout(completion, msecs_to_jiffies(2000)) ? 0 : -ETIME;
125 }
126
127 static int smsdvb_send_statistics_request(smsdvb_client_t *client)
128 {
129         SmsMsgHdr_ST Msg = { MSG_SMS_GET_STATISTICS_REQ, DVBT_BDA_CONTROL_MSG_ID, HIF_TASK, sizeof(SmsMsgHdr_ST), 0 };
130         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->stat_done);
131 }
132
133 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
134 {
135         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
136         int rc = smsdvb_send_statistics_request(client);
137
138         if (!rc)
139                 *stat = client->fe_status;
140
141         return rc;
142 }
143
144 static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
145 {
146         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
147         int rc = smsdvb_send_statistics_request(client);
148
149         if (!rc)
150                 *ber = client->fe_ber;
151
152         return rc;
153 }
154
155 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
156 {
157         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
158         int rc = smsdvb_send_statistics_request(client);
159
160         if (!rc)
161                 *strength = client->fe_signal_strength;
162
163         return rc;
164 }
165
166 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
167 {
168         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
169         int rc = smsdvb_send_statistics_request(client);
170
171         if (!rc)
172                 *snr = client->fe_snr;
173
174         return rc;
175 }
176
177 static int smsdvb_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
178 {
179         printk("%s\n", __FUNCTION__);
180
181         tune->min_delay_ms = 400;
182         tune->step_size = 250000;
183         tune->max_drift = 0;
184         return 0;
185 }
186
187 static int smsdvb_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
188 {
189         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
190
191         struct
192         {
193                 SmsMsgHdr_ST    Msg;
194                 u32                             Data[3];
195         } Msg;
196
197         Msg.Msg.msgSrcId  = DVBT_BDA_CONTROL_MSG_ID;
198         Msg.Msg.msgDstId  = HIF_TASK;
199         Msg.Msg.msgFlags  = 0;
200         Msg.Msg.msgType   = MSG_SMS_RF_TUNE_REQ;
201         Msg.Msg.msgLength = sizeof(Msg);
202         Msg.Data[0] = fep->frequency;
203         Msg.Data[2] = 12000000;
204
205         printk("%s freq %d band %d\n", __FUNCTION__, fep->frequency, fep->u.ofdm.bandwidth);
206
207         switch(fep->u.ofdm.bandwidth)
208         {
209                 case BANDWIDTH_8_MHZ: Msg.Data[1] = BW_8_MHZ; break;
210                 case BANDWIDTH_7_MHZ: Msg.Data[1] = BW_7_MHZ; break;
211                 case BANDWIDTH_6_MHZ: Msg.Data[1] = BW_6_MHZ; break;
212 //              case BANDWIDTH_5_MHZ: Msg.Data[1] = BW_5_MHZ; break;
213                 case BANDWIDTH_AUTO: return -EOPNOTSUPP;
214                 default: return -EINVAL;
215         }
216
217         return smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg), &client->tune_done);
218 }
219
220 static int smsdvb_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
221 {
222         smsdvb_client_t *client = container_of(fe, smsdvb_client_t, frontend);
223
224         printk("%s\n", __FUNCTION__);
225
226         // todo:
227         memcpy(fep, &client->fe_params, sizeof(struct dvb_frontend_parameters));
228         return 0;
229 }
230
231 static void smsdvb_release(struct dvb_frontend *fe)
232 {
233         // do nothing
234 }
235
236 static struct dvb_frontend_ops smsdvb_fe_ops = {
237         .info = {
238                 .name                           = "Siano Mobile Digital SMS10xx",
239                 .type                           = FE_OFDM,
240                 .frequency_min          = 44250000,
241                 .frequency_max          = 867250000,
242                 .frequency_stepsize     = 250000,
243                 .caps = FE_CAN_INVERSION_AUTO |
244                                 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
245                                 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
246                                 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
247                                 FE_CAN_TRANSMISSION_MODE_AUTO |
248                                 FE_CAN_GUARD_INTERVAL_AUTO |
249                                 FE_CAN_RECOVER |
250                                 FE_CAN_HIERARCHY_AUTO,
251         },
252
253         .release = smsdvb_release,
254
255         .set_frontend = smsdvb_set_frontend,
256         .get_frontend = smsdvb_get_frontend,
257         .get_tune_settings = smsdvb_get_tune_settings,
258
259         .read_status = smsdvb_read_status,
260         .read_ber = smsdvb_read_ber,
261         .read_signal_strength = smsdvb_read_signal_strength,
262         .read_snr = smsdvb_read_snr,
263 };
264
265 int smsdvb_hotplug(smscore_device_t *coredev, struct device* device, int arrival)
266 {
267         smsclient_params_t params;
268         smsdvb_client_t* client;
269         int rc;
270
271         // device removal handled by onremove callback
272         if (!arrival)
273                 return 0;
274
275         if (smscore_get_device_mode(coredev) != 4)
276         {
277                 rc = smscore_set_device_mode(coredev, 4);
278                 if (rc < 0)
279                         return rc;
280         }
281
282         client = kzalloc(sizeof(smsdvb_client_t), GFP_KERNEL);
283         if (!client)
284         {
285                 printk(KERN_INFO "%s kmalloc() failed\n", __FUNCTION__);
286                 return -ENOMEM;
287         }
288
289         // register dvb adapter
290         rc = dvb_register_adapter(&client->adapter, "Siano Digital Receiver", THIS_MODULE, device, adapter_nr);
291         if (rc < 0)
292         {
293                 printk("%s dvb_register_adapter() failed %d\n", __func__, rc);
294                 goto adapter_error;
295         }
296
297         // init dvb demux
298         client->demux.dmx.capabilities = DMX_TS_FILTERING;
299         client->demux.filternum = 32; // todo: nova ???
300         client->demux.feednum = 32;
301         client->demux.start_feed = smsdvb_start_feed;
302         client->demux.stop_feed = smsdvb_stop_feed;
303
304         rc = dvb_dmx_init(&client->demux);
305         if (rc < 0)
306         {
307                 printk("%s dvb_dmx_init failed %d\n\n", __FUNCTION__, rc);
308                 goto dvbdmx_error;
309         }
310
311         // init dmxdev
312         client->dmxdev.filternum = 32;
313         client->dmxdev.demux = &client->demux.dmx;
314         client->dmxdev.capabilities = 0;
315
316         rc = dvb_dmxdev_init(&client->dmxdev, &client->adapter);
317         if (rc < 0)
318         {
319                 printk("%s dvb_dmxdev_init failed %d\n", __FUNCTION__, rc);
320                 goto dmxdev_error;
321         }
322
323         // init and register frontend
324         memcpy(&client->frontend.ops, &smsdvb_fe_ops, sizeof(struct dvb_frontend_ops));
325
326         rc = dvb_register_frontend(&client->adapter, &client->frontend);
327         if (rc < 0)
328         {
329                 printk("%s frontend registration failed %d\n", __FUNCTION__, rc);
330                 goto frontend_error;
331         }
332
333         params.initial_id = 0;
334         params.data_type = MSG_SMS_DVBT_BDA_DATA;
335         params.onresponse_handler = smsdvb_onresponse;
336         params.onremove_handler = smsdvb_onremove;
337         params.context = client;
338
339         rc = smscore_register_client(coredev, &params, &client->smsclient);
340         if (rc < 0)
341         {
342                 printk(KERN_INFO "%s smscore_register_client() failed %d\n", __FUNCTION__, rc);
343                 goto client_error;
344         }
345
346         client->coredev = coredev;
347
348         init_completion(&client->tune_done);
349         init_completion(&client->stat_done);
350
351         kmutex_lock(&g_smsdvb_clientslock);
352
353         list_add(&client->entry, &g_smsdvb_clients);
354
355         kmutex_unlock(&g_smsdvb_clientslock);
356
357         printk(KERN_INFO "%s success\n", __FUNCTION__);
358
359         return 0;
360
361 client_error:
362         dvb_unregister_frontend(&client->frontend);
363
364 frontend_error:
365         dvb_dmxdev_release(&client->dmxdev);
366
367 dmxdev_error:
368         dvb_dmx_release(&client->demux);
369
370 dvbdmx_error:
371         dvb_unregister_adapter(&client->adapter);
372
373 adapter_error:
374         kfree(client);
375         return rc;
376 }
377