aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/dvb-usb/gp8psk-fe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/dvb/dvb-usb/gp8psk-fe.c')
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
new file mode 100644
index 000000000000..6ccbdc9cd772
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -0,0 +1,272 @@
1/* DVB USB compliant Linux driver for the
2 * - GENPIX 8pks/qpsk USB2.0 DVB-S module
3 *
4 * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
5 *
6 * Thanks to GENPIX for the sample code used to implement this module.
7 *
8 * This module is based off the vp7045 and vp702x modules
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation, version 2.
13 *
14 * see Documentation/dvb/README.dvb-usb for more information
15 */
16#include "gp8psk.h"
17
18struct gp8psk_fe_state {
19 struct dvb_frontend fe;
20
21 struct dvb_usb_device *d;
22
23 u16 snr;
24
25 unsigned long next_snr_check;
26};
27
28static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
29{
30 struct gp8psk_fe_state *st = fe->demodulator_priv;
31 u8 lock;
32
33 if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
34 return -EINVAL;
35
36 if (lock)
37 *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
38 else
39 *status = 0;
40
41 return 0;
42}
43
44/* not supported by this Frontend */
45static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
46{
47 (void) fe;
48 *ber = 0;
49 return 0;
50}
51
52/* not supported by this Frontend */
53static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
54{
55 (void) fe;
56 *unc = 0;
57 return 0;
58}
59
60static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
61{
62 struct gp8psk_fe_state *st = fe->demodulator_priv;
63 u8 buf[2];
64
65 if (time_after(jiffies,st->next_snr_check)) {
66 gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
67 *snr = (int)(buf[1]) << 8 | buf[0];
68 /* snr is reported in dBu*256 */
69 /* snr / 38.4 ~= 100% strength */
70 /* snr * 17 returns 100% strength as 65535 */
71 if (*snr <= 3855)
72 *snr = (*snr<<4) + *snr; // snr * 17
73 else
74 *snr = 65535;
75 st->next_snr_check = jiffies + (10*HZ)/1000;
76 } else {
77 *snr = st->snr;
78 }
79 return 0;
80}
81
82static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
83{
84 return gp8psk_fe_read_snr(fe, strength);
85}
86
87static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
88{
89 tune->min_delay_ms = 800;
90 return 0;
91}
92
93static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
94 struct dvb_frontend_parameters *fep)
95{
96 struct gp8psk_fe_state *state = fe->demodulator_priv;
97 u8 cmd[10];
98 u32 freq = fep->frequency * 1000;
99
100 cmd[4] = freq & 0xff;
101 cmd[5] = (freq >> 8) & 0xff;
102 cmd[6] = (freq >> 16) & 0xff;
103 cmd[7] = (freq >> 24) & 0xff;
104
105 switch(fe->ops.info.type) {
106 case FE_QPSK:
107 cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
108 cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
109 cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
110 cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
111 cmd[8] = ADV_MOD_DVB_QPSK;
112 cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
113 break;
114 default:
115 // other modes are unsuported right now
116 cmd[0] = 0;
117 cmd[1] = 0;
118 cmd[2] = 0;
119 cmd[3] = 0;
120 cmd[8] = 0;
121 cmd[9] = 0;
122 break;
123 }
124
125 gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
126
127 state->next_snr_check = jiffies;
128
129 return 0;
130}
131
132static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
133 struct dvb_frontend_parameters *fep)
134{
135 return 0;
136}
137
138
139static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
140 struct dvb_diseqc_master_cmd *m)
141{
142 struct gp8psk_fe_state *st = fe->demodulator_priv;
143
144 deb_fe("%s\n",__FUNCTION__);
145
146 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
147 m->msg, m->msg_len)) {
148 return -EINVAL;
149 }
150 return 0;
151}
152
153static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
154 fe_sec_mini_cmd_t burst)
155{
156 struct gp8psk_fe_state *st = fe->demodulator_priv;
157 u8 cmd;
158
159 deb_fe("%s\n",__FUNCTION__);
160
161 /* These commands are certainly wrong */
162 cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
163
164 if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
165 &cmd, 0)) {
166 return -EINVAL;
167 }
168 return 0;
169}
170
171static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
172{
173 struct gp8psk_fe_state* state = fe->demodulator_priv;
174
175 if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
176 (tone == SEC_TONE_ON), 0, NULL, 0)) {
177 return -EINVAL;
178 }
179 return 0;
180}
181
182static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
183{
184 struct gp8psk_fe_state* state = fe->demodulator_priv;
185
186 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
187 voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
188 return -EINVAL;
189 }
190 return 0;
191}
192
193static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
194{
195 struct gp8psk_fe_state* state = fe->demodulator_priv;
196 u8 cmd = sw_cmd & 0x7f;
197
198 if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
199 NULL, 0)) {
200 return -EINVAL;
201 }
202 if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
203 0, NULL, 0)) {
204 return -EINVAL;
205 }
206
207 return 0;
208}
209
210static void gp8psk_fe_release(struct dvb_frontend* fe)
211{
212 struct gp8psk_fe_state *state = fe->demodulator_priv;
213 kfree(state);
214}
215
216static struct dvb_frontend_ops gp8psk_fe_ops;
217
218struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
219{
220 struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
221 if (s == NULL)
222 goto error;
223
224 s->d = d;
225 memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
226 s->fe.demodulator_priv = s;
227
228 goto success;
229error:
230 return NULL;
231success:
232 return &s->fe;
233}
234
235
236static struct dvb_frontend_ops gp8psk_fe_ops = {
237 .info = {
238 .name = "Genpix 8psk-USB DVB-S",
239 .type = FE_QPSK,
240 .frequency_min = 950000,
241 .frequency_max = 2150000,
242 .frequency_stepsize = 100,
243 .symbol_rate_min = 1000000,
244 .symbol_rate_max = 45000000,
245 .symbol_rate_tolerance = 500, /* ppm */
246 .caps = FE_CAN_INVERSION_AUTO |
247 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
248 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
249 FE_CAN_QPSK
250 },
251
252 .release = gp8psk_fe_release,
253
254 .init = NULL,
255 .sleep = NULL,
256
257 .set_frontend = gp8psk_fe_set_frontend,
258 .get_frontend = gp8psk_fe_get_frontend,
259 .get_tune_settings = gp8psk_fe_get_tune_settings,
260
261 .read_status = gp8psk_fe_read_status,
262 .read_ber = gp8psk_fe_read_ber,
263 .read_signal_strength = gp8psk_fe_read_signal_strength,
264 .read_snr = gp8psk_fe_read_snr,
265 .read_ucblocks = gp8psk_fe_read_unc_blocks,
266
267 .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
268 .diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
269 .set_tone = gp8psk_fe_set_tone,
270 .set_voltage = gp8psk_fe_set_voltage,
271 .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
272};