firedtv: Use DEFINE_SPINLOCK
[pandora-kernel.git] / drivers / media / dvb / firesat / firesat_fe.c
1 /*
2  * FireDTV driver (formerly known as FireSAT)
3  *
4  * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5  * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
6  *
7  *      This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License as
9  *      published by the Free Software Foundation; either version 2 of
10  *      the License, or (at your option) any later version.
11  */
12
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/string.h>
16 #include <linux/types.h>
17
18 #include <dvb_frontend.h>
19
20 #include "avc_api.h"
21 #include "cmp.h"
22 #include "firesat.h"
23
24 static int firesat_dvb_init(struct dvb_frontend *fe)
25 {
26         struct firesat *firesat = fe->sec_priv;
27         int err;
28
29         /* FIXME - allocate free channel at IRM */
30         firesat->isochannel = firesat->adapter.num;
31
32         err = cmp_establish_pp_connection(firesat, firesat->subunit,
33                                           firesat->isochannel);
34         if (err) {
35                 printk(KERN_ERR "Could not establish point to point "
36                        "connection.\n");
37                 return err;
38         }
39
40         return setup_iso_channel(firesat);
41 }
42
43 static int firesat_sleep(struct dvb_frontend *fe)
44 {
45         struct firesat *firesat = fe->sec_priv;
46
47         tear_down_iso_channel(firesat);
48         cmp_break_pp_connection(firesat, firesat->subunit, firesat->isochannel);
49         firesat->isochannel = -1;
50         return 0;
51 }
52
53 static int firesat_diseqc_send_master_cmd(struct dvb_frontend *fe,
54                                           struct dvb_diseqc_master_cmd *cmd)
55 {
56         struct firesat *firesat = fe->sec_priv;
57
58         return avc_lnb_control(firesat, LNBCONTROL_DONTCARE,
59                         LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE, 1, cmd);
60 }
61
62 static int firesat_diseqc_send_burst(struct dvb_frontend *fe,
63                                      fe_sec_mini_cmd_t minicmd)
64 {
65         return 0;
66 }
67
68 static int firesat_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
69 {
70         struct firesat *firesat = fe->sec_priv;
71
72         firesat->tone = tone;
73         return 0;
74 }
75
76 static int firesat_set_voltage(struct dvb_frontend *fe,
77                                fe_sec_voltage_t voltage)
78 {
79         struct firesat *firesat = fe->sec_priv;
80
81         firesat->voltage = voltage;
82         return 0;
83 }
84
85 static int firesat_read_status(struct dvb_frontend *fe, fe_status_t *status)
86 {
87         struct firesat *firesat = fe->sec_priv;
88         ANTENNA_INPUT_INFO info;
89
90         if (avc_tuner_status(firesat, &info))
91                 return -EINVAL;
92
93         if (info.NoRF)
94                 *status = 0;
95         else
96                 *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
97                           FE_HAS_CARRIER | FE_HAS_LOCK;
98         return 0;
99 }
100
101 static int firesat_read_ber(struct dvb_frontend *fe, u32 *ber)
102 {
103         struct firesat *firesat = fe->sec_priv;
104         ANTENNA_INPUT_INFO info;
105
106         if (avc_tuner_status(firesat, &info))
107                 return -EINVAL;
108
109         *ber = info.BER[0] << 24 | info.BER[1] << 16 |
110                info.BER[2] << 8 | info.BER[3];
111         return 0;
112 }
113
114 static int firesat_read_signal_strength (struct dvb_frontend *fe, u16 *strength)
115 {
116         struct firesat *firesat = fe->sec_priv;
117         ANTENNA_INPUT_INFO info;
118
119         if (avc_tuner_status(firesat, &info))
120                 return -EINVAL;
121
122         *strength = info.SignalStrength << 8;
123         return 0;
124 }
125
126 static int firesat_read_snr(struct dvb_frontend *fe, u16 *snr)
127 {
128         struct firesat *firesat = fe->sec_priv;
129         ANTENNA_INPUT_INFO info;
130
131         if (avc_tuner_status(firesat, &info))
132                 return -EINVAL;
133
134         /* C/N[dB] = -10 * log10(snr / 65535) */
135         *snr = (info.CarrierNoiseRatio[0] << 8) + info.CarrierNoiseRatio[1];
136         *snr *= 257;
137         return 0;
138 }
139
140 static int firesat_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
141 {
142         return -EOPNOTSUPP;
143 }
144
145 static int firesat_set_frontend(struct dvb_frontend *fe,
146                                 struct dvb_frontend_parameters *params)
147 {
148         struct firesat *firesat = fe->sec_priv;
149
150         /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */
151         if (avc_tuner_dsd(firesat, params) != ACCEPTED)
152                 return -EINVAL;
153         else
154                 return 0; /* not sure of this... */
155 }
156
157 static int firesat_get_frontend(struct dvb_frontend *fe,
158                                 struct dvb_frontend_parameters *params)
159 {
160         return -EOPNOTSUPP;
161 }
162
163 void firesat_frontend_init(struct firesat *firesat)
164 {
165         struct dvb_frontend_ops *ops = &firesat->fe.ops;
166         struct dvb_frontend_info *fi = &ops->info;
167
168         ops->init                       = firesat_dvb_init;
169         ops->sleep                      = firesat_sleep;
170
171         ops->set_frontend               = firesat_set_frontend;
172         ops->get_frontend               = firesat_get_frontend;
173
174         ops->read_status                = firesat_read_status;
175         ops->read_ber                   = firesat_read_ber;
176         ops->read_signal_strength       = firesat_read_signal_strength;
177         ops->read_snr                   = firesat_read_snr;
178         ops->read_ucblocks              = firesat_read_uncorrected_blocks;
179
180         ops->diseqc_send_master_cmd     = firesat_diseqc_send_master_cmd;
181         ops->diseqc_send_burst          = firesat_diseqc_send_burst;
182         ops->set_tone                   = firesat_set_tone;
183         ops->set_voltage                = firesat_set_voltage;
184
185         switch (firesat->type) {
186         case FireSAT_DVB_S:
187                 fi->type                = FE_QPSK;
188
189                 fi->frequency_min       = 950000;
190                 fi->frequency_max       = 2150000;
191                 fi->frequency_stepsize  = 125;
192                 fi->symbol_rate_min     = 1000000;
193                 fi->symbol_rate_max     = 40000000;
194
195                 fi->caps                = FE_CAN_INVERSION_AUTO |
196                                           FE_CAN_FEC_1_2        |
197                                           FE_CAN_FEC_2_3        |
198                                           FE_CAN_FEC_3_4        |
199                                           FE_CAN_FEC_5_6        |
200                                           FE_CAN_FEC_7_8        |
201                                           FE_CAN_FEC_AUTO       |
202                                           FE_CAN_QPSK;
203                 break;
204
205         case FireSAT_DVB_C:
206                 fi->type                = FE_QAM;
207
208                 fi->frequency_min       = 47000000;
209                 fi->frequency_max       = 866000000;
210                 fi->frequency_stepsize  = 62500;
211                 fi->symbol_rate_min     = 870000;
212                 fi->symbol_rate_max     = 6900000;
213
214                 fi->caps                = FE_CAN_INVERSION_AUTO |
215                                           FE_CAN_QAM_16         |
216                                           FE_CAN_QAM_32         |
217                                           FE_CAN_QAM_64         |
218                                           FE_CAN_QAM_128        |
219                                           FE_CAN_QAM_256        |
220                                           FE_CAN_QAM_AUTO;
221                 break;
222
223         case FireSAT_DVB_T:
224                 fi->type                = FE_OFDM;
225
226                 fi->frequency_min       = 49000000;
227                 fi->frequency_max       = 861000000;
228                 fi->frequency_stepsize  = 62500;
229
230                 fi->caps                = FE_CAN_INVERSION_AUTO         |
231                                           FE_CAN_FEC_2_3                |
232                                           FE_CAN_TRANSMISSION_MODE_AUTO |
233                                           FE_CAN_GUARD_INTERVAL_AUTO    |
234                                           FE_CAN_HIERARCHY_AUTO;
235                 break;
236
237         default:
238                 printk(KERN_ERR "FireDTV: no frontend for model type %d\n",
239                        firesat->type);
240         }
241         strcpy(fi->name, firedtv_model_names[firesat->type]);
242
243         firesat->fe.dvb = &firesat->adapter;
244         firesat->fe.sec_priv = firesat;
245 }