The DVB binding schema at the DVB core assumes that the frontend is a separate driver. Faling to do that causes OOPS when the module is removed, as it tries to do a symbol_put_addr on an internal symbol, causing craches like: WARNING: CPU: 1 PID: 28102 at kernel/module.c:1108 module_put+0x57/0x70 Modules linked in: dvb_usb_gp8psk(-) dvb_usb dvb_core nvidia_drm(PO) nvidia_modeset(PO) snd_hda_codec_hdmi snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_pcm snd_timer snd soundcore nvidia(PO) [last unloaded: rc_core] CPU: 1 PID: 28102 Comm: rmmod Tainted: P WC O 4.8.4-build.1 #1 Hardware name: MSI MS-7309/MS-7309, BIOS V1.12 02/23/2009 Call Trace: dump_stack+0x44/0x64 __warn+0xfa/0x120 module_put+0x57/0x70 module_put+0x57/0x70 warn_slowpath_null+0x23/0x30 module_put+0x57/0x70 gp8psk_fe_set_frontend+0x460/0x460 [dvb_usb_gp8psk] symbol_put_addr+0x27/0x50 dvb_usb_adapter_frontend_exit+0x3a/0x70 [dvb_usb] From Derek's tests: "Attach bug is fixed, tuning works, module unloads without crashing. Everything seems ok!"
Unified · Split
| @@ -513,6 +513,11 @@ config DVB_AS102_FE · 512 unmodified lines | ||
| 513 | 513 | depends on DVB_CORE |
| 514 | 514 | default DVB_AS102 |
| 515 | 515 | |
| 516 | +config DVB_GP8PSK_FE | |
| 517 | + tristate | |
| 518 | + depends on DVB_CORE | |
| 519 | + default DVB_USB_GP8PSK | |
| 520 | + | |
| 516 | 521 | comment "DVB-C (cable) frontends" |
| 517 | 522 | depends on DVB_CORE |
| 518 | 523 | |
| @@ -121,6 +121,7 @@ obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o · 120 unmodified lines | ||
| 121 | 121 | obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o |
| 122 | 122 | obj-$(CONFIG_DVB_AF9033) += af9033.o |
| 123 | 123 | obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o |
| 124 | +obj-$(CONFIG_DVB_GP8PSK_FE) += gp8psk-fe.o | |
| 124 | 125 | obj-$(CONFIG_DVB_TC90522) += tc90522.o |
| 125 | 126 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o |
| 126 | 127 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o |
| @@ -14,11 +14,27 @@ · 13 unmodified lines | ||
| 14 | 14 | * |
| 15 | 15 | * see Documentation/dvb/README.dvb-usb for more information |
| 16 | 16 | */ |
| 17 | −#include "gp8psk.h" | |
| 17 | + | |
| 18 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
| 19 | + | |
| 20 | +#include "gp8psk-fe.h" | |
| 21 | +#include "dvb_frontend.h" | |
| 22 | + | |
| 23 | +static int debug; | |
| 24 | +module_param(debug, int, 0644); | |
| 25 | +MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | |
| 26 | + | |
| 27 | +#define dprintk(fmt, arg...) do { \ | |
| 28 | + if (debug) \ | |
| 29 | + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ | |
| 30 | + __func__, ##arg); \ | |
| 31 | +} while (0) | |
| 18 | 32 | |
| 19 | 33 | struct gp8psk_fe_state { |
| 20 | 34 | struct dvb_frontend fe; |
| 21 | − struct dvb_usb_device *d; | |
| 35 | + void *priv; | |
| 36 | + const struct gp8psk_fe_ops *ops; | |
| 37 | + bool is_rev1; | |
| 22 | 38 | u8 lock; |
| 23 | 39 | u16 snr; |
| 24 | 40 | unsigned long next_status_check; |
| @@ -29,22 +45,24 @@ static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 29 | 45 | { |
| 30 | 46 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 31 | 47 | u8 status; |
| 32 | − gp8psk_usb_in_op(st->d, GET_8PSK_CONFIG, 0, 0, &status, 1); | |
| 48 | + | |
| 49 | + st->ops->in(st->priv, GET_8PSK_CONFIG, 0, 0, &status, 1); | |
| 33 | 50 | return status & bmDCtuned; |
| 34 | 51 | } |
| 35 | 52 | |
| 36 | 53 | static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) |
| 37 | 54 | { |
| 38 | − struct gp8psk_fe_state *state = fe->demodulator_priv; | |
| 39 | − return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); | |
| 55 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 56 | + | |
| 57 | + return st->ops->out(st->priv, SET_8PSK_CONFIG, mode, 0, NULL, 0); | |
| 40 | 58 | } |
| 41 | 59 | |
| 42 | 60 | static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) |
| 43 | 61 | { |
| 44 | 62 | u8 buf[6]; |
| 45 | 63 | if (time_after(jiffies,st->next_status_check)) { |
| 46 | − gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); | |
| 47 | − gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); | |
| 64 | + st->ops->in(st->priv, GET_SIGNAL_LOCK, 0, 0, &st->lock, 1); | |
| 65 | + st->ops->in(st->priv, GET_SIGNAL_STRENGTH, 0, 0, buf, 6); | |
| 48 | 66 | st->snr = (buf[1]) << 8 | buf[0]; |
| 49 | 67 | st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; |
| 50 | 68 | } |
| @@ -116,13 +134,12 @@ static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_front · 65 unmodified lines | ||
| 116 | 134 | |
| 117 | 135 | static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) |
| 118 | 136 | { |
| 119 | − struct gp8psk_fe_state *state = fe->demodulator_priv; | |
| 137 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 120 | 138 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 121 | 139 | u8 cmd[10]; |
| 122 | 140 | u32 freq = c->frequency * 1000; |
| 123 | − int gp_product_id = le16_to_cpu(state->d->udev->descriptor.idProduct); | |
| 124 | 141 | |
| 125 | − deb_fe("%s()\n", __func__); | |
| 142 | + dprintk("%s()\n", __func__); | |
| 126 | 143 | |
| 127 | 144 | cmd[4] = freq & 0xff; |
| 128 | 145 | cmd[5] = (freq >> 8) & 0xff; |
| @@ -136,21 +153,21 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) · 7 unmodified lines | ||
| 136 | 153 | switch (c->delivery_system) { |
| 137 | 154 | case SYS_DVBS: |
| 138 | 155 | if (c->modulation != QPSK) { |
| 139 | − deb_fe("%s: unsupported modulation selected (%d)\n", | |
| 156 | + dprintk("%s: unsupported modulation selected (%d)\n", | |
| 140 | 157 | __func__, c->modulation); |
| 141 | 158 | return -EOPNOTSUPP; |
| 142 | 159 | } |
| 143 | 160 | c->fec_inner = FEC_AUTO; |
| 144 | 161 | break; |
| 145 | 162 | case SYS_DVBS2: /* kept for backwards compatibility */ |
| 146 | − deb_fe("%s: DVB-S2 delivery system selected\n", __func__); | |
| 163 | + dprintk("%s: DVB-S2 delivery system selected\n", __func__); | |
| 147 | 164 | break; |
| 148 | 165 | case SYS_TURBO: |
| 149 | − deb_fe("%s: Turbo-FEC delivery system selected\n", __func__); | |
| 166 | + dprintk("%s: Turbo-FEC delivery system selected\n", __func__); | |
| 150 | 167 | break; |
| 151 | 168 | |
| 152 | 169 | default: |
| 153 | − deb_fe("%s: unsupported delivery system selected (%d)\n", | |
| 170 | + dprintk("%s: unsupported delivery system selected (%d)\n", | |
| 154 | 171 | __func__, c->delivery_system); |
| 155 | 172 | return -EOPNOTSUPP; |
| 156 | 173 | } |
| @@ -161,9 +178,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) · 4 unmodified lines | ||
| 161 | 178 | cmd[3] = (c->symbol_rate >> 24) & 0xff; |
| 162 | 179 | switch (c->modulation) { |
| 163 | 180 | case QPSK: |
| 164 | − if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | |
| 181 | + if (st->is_rev1) | |
| 165 | 182 | if (gp8psk_tuned_to_DCII(fe)) |
| 166 | − gp8psk_bcm4500_reload(state->d); | |
| 183 | + st->ops->reload(st->priv); | |
| 167 | 184 | switch (c->fec_inner) { |
| 168 | 185 | case FEC_1_2: |
| 169 | 186 | cmd[9] = 0; break; |
| @@ -207,18 +224,18 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) · 37 unmodified lines | ||
| 207 | 224 | cmd[9] = 0; |
| 208 | 225 | break; |
| 209 | 226 | default: /* Unknown modulation */ |
| 210 | − deb_fe("%s: unsupported modulation selected (%d)\n", | |
| 227 | + dprintk("%s: unsupported modulation selected (%d)\n", | |
| 211 | 228 | __func__, c->modulation); |
| 212 | 229 | return -EOPNOTSUPP; |
| 213 | 230 | } |
| 214 | 231 | |
| 215 | − if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | |
| 232 | + if (st->is_rev1) | |
| 216 | 233 | gp8psk_set_tuner_mode(fe, 0); |
| 217 | − gp8psk_usb_out_op(state->d, TUNE_8PSK, 0, 0, cmd, 10); | |
| 234 | + st->ops->out(st->priv, TUNE_8PSK, 0, 0, cmd, 10); | |
| 218 | 235 | |
| 219 | − state->lock = 0; | |
| 220 | − state->next_status_check = jiffies; | |
| 221 | − state->status_check_interval = 200; | |
| 236 | + st->lock = 0; | |
| 237 | + st->next_status_check = jiffies; | |
| 238 | + st->status_check_interval = 200; | |
| 222 | 239 | |
| 223 | 240 | return 0; |
| 224 | 241 | } |
| @@ -228,9 +245,9 @@ static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, · 3 unmodified lines | ||
| 228 | 245 | { |
| 229 | 246 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 230 | 247 | |
| 231 | − deb_fe("%s\n",__func__); | |
| 248 | + dprintk("%s\n", __func__); | |
| 232 | 249 | |
| 233 | − if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, | |
| 250 | + if (st->ops->out(st->priv, SEND_DISEQC_COMMAND, m->msg[0], 0, | |
| 234 | 251 | m->msg, m->msg_len)) { |
| 235 | 252 | return -EINVAL; |
| 236 | 253 | } |
| @@ -243,12 +260,12 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe, · 6 unmodified lines | ||
| 243 | 260 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 244 | 261 | u8 cmd; |
| 245 | 262 | |
| 246 | − deb_fe("%s\n",__func__); | |
| 263 | + dprintk("%s\n", __func__); | |
| 247 | 264 | |
| 248 | 265 | /* These commands are certainly wrong */ |
| 249 | 266 | cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; |
| 250 | 267 | |
| 251 | − if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, | |
| 268 | + if (st->ops->out(st->priv, SEND_DISEQC_COMMAND, cmd, 0, | |
| 252 | 269 | &cmd, 0)) { |
| 253 | 270 | return -EINVAL; |
| 254 | 271 | } |
| @@ -258,10 +275,10 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe, · 3 unmodified lines | ||
| 258 | 275 | static int gp8psk_fe_set_tone(struct dvb_frontend *fe, |
| 259 | 276 | enum fe_sec_tone_mode tone) |
| 260 | 277 | { |
| 261 | − struct gp8psk_fe_state* state = fe->demodulator_priv; | |
| 278 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 262 | 279 | |
| 263 | − if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, | |
| 264 | − (tone == SEC_TONE_ON), 0, NULL, 0)) { | |
| 280 | + if (st->ops->out(st->priv, SET_22KHZ_TONE, | |
| 281 | + (tone == SEC_TONE_ON), 0, NULL, 0)) { | |
| 265 | 282 | return -EINVAL; |
| 266 | 283 | } |
| 267 | 284 | return 0; |
| @@ -270,9 +287,9 @@ static int gp8psk_fe_set_tone(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 270 | 287 | static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, |
| 271 | 288 | enum fe_sec_voltage voltage) |
| 272 | 289 | { |
| 273 | − struct gp8psk_fe_state* state = fe->demodulator_priv; | |
| 290 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 274 | 291 | |
| 275 | − if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, | |
| 292 | + if (st->ops->out(st->priv, SET_LNB_VOLTAGE, | |
| 276 | 293 | voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { |
| 277 | 294 | return -EINVAL; |
| 278 | 295 | } |
| @@ -281,52 +298,60 @@ static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, · 2 unmodified lines | ||
| 281 | 298 | |
| 282 | 299 | static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) |
| 283 | 300 | { |
| 284 | − struct gp8psk_fe_state* state = fe->demodulator_priv; | |
| 285 | − return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); | |
| 301 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 302 | + | |
| 303 | + return st->ops->out(st->priv, USE_EXTRA_VOLT, onoff, 0, NULL, 0); | |
| 286 | 304 | } |
| 287 | 305 | |
| 288 | 306 | static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) |
| 289 | 307 | { |
| 290 | − struct gp8psk_fe_state* state = fe->demodulator_priv; | |
| 308 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 291 | 309 | u8 cmd = sw_cmd & 0x7f; |
| 292 | 310 | |
| 293 | − if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, | |
| 294 | − NULL, 0)) { | |
| 311 | + if (st->ops->out(st->priv, SET_DN_SWITCH, cmd, 0, NULL, 0)) | |
| 295 | 312 | return -EINVAL; |
| 296 | − } | |
| 297 | − if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), | |
| 298 | − 0, NULL, 0)) { | |
| 313 | + | |
| 314 | + if (st->ops->out(st->priv, SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), | |
| 315 | + 0, NULL, 0)) | |
| 299 | 316 | return -EINVAL; |
| 300 | − } | |
| 301 | 317 | |
| 302 | 318 | return 0; |
| 303 | 319 | } |
| 304 | 320 | |
| 305 | 321 | static void gp8psk_fe_release(struct dvb_frontend* fe) |
| 306 | 322 | { |
| 307 | − struct gp8psk_fe_state *state = fe->demodulator_priv; | |
| 308 | − kfree(state); | |
| 323 | + struct gp8psk_fe_state *st = fe->demodulator_priv; | |
| 324 | + | |
| 325 | + kfree(st); | |
| 309 | 326 | } |
| 310 | 327 | |
| 311 | 328 | static struct dvb_frontend_ops gp8psk_fe_ops; |
| 312 | 329 | |
| 313 | −struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) | |
| 330 | +struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops, | |
| 331 | + void *priv, bool is_rev1) | |
| 314 | 332 | { |
| 315 | − struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); | |
| 316 | − if (s == NULL) | |
| 317 | − goto error; | |
| 318 | − | |
| 319 | − s->d = d; | |
| 320 | − memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); | |
| 321 | − s->fe.demodulator_priv = s; | |
| 322 | − | |
| 323 | − goto success; | |
| 324 | −error: | |
| 325 | − return NULL; | |
| 326 | −success: | |
| 327 | − return &s->fe; | |
| 328 | −} | |
| 333 | + struct gp8psk_fe_state *st; | |
| 329 | 334 | |
| 335 | + if (!ops || !ops->in || !ops->out || !ops->reload) { | |
| 336 | + pr_err("Error! gp8psk-fe ops not defined.\n"); | |
| 337 | + return NULL; | |
| 338 | + } | |
| 339 | + | |
| 340 | + st = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); | |
| 341 | + if (!st) | |
| 342 | + return NULL; | |
| 343 | + | |
| 344 | + memcpy(&st->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); | |
| 345 | + st->fe.demodulator_priv = st; | |
| 346 | + st->ops = ops; | |
| 347 | + st->priv = priv; | |
| 348 | + st->is_rev1 = is_rev1; | |
| 349 | + | |
| 350 | + pr_info("Frontend %sattached\n", is_rev1 ? "revision 1 " : ""); | |
| 351 | + | |
| 352 | + return &st->fe; | |
| 353 | +} | |
| 354 | +EXPORT_SYMBOL_GPL(gp8psk_fe_attach); | |
| 330 | 355 | |
| 331 | 356 | static struct dvb_frontend_ops gp8psk_fe_ops = { |
| 332 | 357 | .delsys = { SYS_DVBS }, |
| @@ -0,0 +1,82 @@ | ||
| 1 | +/* | |
| 2 | + * gp8psk_fe driver | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or modify | |
| 5 | + * it under the terms of the GNU General Public License as published by | |
| 6 | + * the Free Software Foundation; either version 2, or (at your option) | |
| 7 | + * any later version. | |
| 8 | + * | |
| 9 | + * This program is distributed in the hope that it will be useful, | |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 12 | + * GNU General Public License for more details. | |
| 13 | + */ | |
| 14 | + | |
| 15 | +#ifndef GP8PSK_FE_H | |
| 16 | +#define GP8PSK_FE_H | |
| 17 | + | |
| 18 | +#include <linux/types.h> | |
| 19 | + | |
| 20 | +/* gp8psk commands */ | |
| 21 | + | |
| 22 | +#define GET_8PSK_CONFIG 0x80 /* in */ | |
| 23 | +#define SET_8PSK_CONFIG 0x81 | |
| 24 | +#define I2C_WRITE 0x83 | |
| 25 | +#define I2C_READ 0x84 | |
| 26 | +#define ARM_TRANSFER 0x85 | |
| 27 | +#define TUNE_8PSK 0x86 | |
| 28 | +#define GET_SIGNAL_STRENGTH 0x87 /* in */ | |
| 29 | +#define LOAD_BCM4500 0x88 | |
| 30 | +#define BOOT_8PSK 0x89 /* in */ | |
| 31 | +#define START_INTERSIL 0x8A /* in */ | |
| 32 | +#define SET_LNB_VOLTAGE 0x8B | |
| 33 | +#define SET_22KHZ_TONE 0x8C | |
| 34 | +#define SEND_DISEQC_COMMAND 0x8D | |
| 35 | +#define SET_DVB_MODE 0x8E | |
| 36 | +#define SET_DN_SWITCH 0x8F | |
| 37 | +#define GET_SIGNAL_LOCK 0x90 /* in */ | |
| 38 | +#define GET_FW_VERS 0x92 | |
| 39 | +#define GET_SERIAL_NUMBER 0x93 /* in */ | |
| 40 | +#define USE_EXTRA_VOLT 0x94 | |
| 41 | +#define GET_FPGA_VERS 0x95 | |
| 42 | +#define CW3K_INIT 0x9d | |
| 43 | + | |
| 44 | +/* PSK_configuration bits */ | |
| 45 | +#define bm8pskStarted 0x01 | |
| 46 | +#define bm8pskFW_Loaded 0x02 | |
| 47 | +#define bmIntersilOn 0x04 | |
| 48 | +#define bmDVBmode 0x08 | |
| 49 | +#define bm22kHz 0x10 | |
| 50 | +#define bmSEL18V 0x20 | |
| 51 | +#define bmDCtuned 0x40 | |
| 52 | +#define bmArmed 0x80 | |
| 53 | + | |
| 54 | +/* Satellite modulation modes */ | |
| 55 | +#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ | |
| 56 | +#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ | |
| 57 | +#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ | |
| 58 | +#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ | |
| 59 | + | |
| 60 | +#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ | |
| 61 | +#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ | |
| 62 | +#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ | |
| 63 | +#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ | |
| 64 | +#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ | |
| 65 | +#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ | |
| 66 | + | |
| 67 | +/* firmware revision id's */ | |
| 68 | +#define GP8PSK_FW_REV1 0x020604 | |
| 69 | +#define GP8PSK_FW_REV2 0x020704 | |
| 70 | +#define GP8PSK_FW_VERS(_fw_vers) \ | |
| 71 | + ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) | |
| 72 | + | |
| 73 | +struct gp8psk_fe_ops { | |
| 74 | + int (*in)(void *priv, u8 req, u16 value, u16 index, u8 *b, int blen); | |
| 75 | + int (*out)(void *priv, u8 req, u16 value, u16 index, u8 *b, int blen); | |
| 76 | + int (*reload)(void *priv); | |
| 77 | +}; | |
| 78 | + | |
| 79 | +struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops, | |
| 80 | + void *priv, bool is_rev1); | |
| 81 | + | |
| 82 | +#endif | |
| @@ -8,7 +8,7 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o · 7 unmodified lines | ||
| 8 | 8 | dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o |
| 9 | 9 | obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o |
| 10 | 10 | |
| 11 | −dvb-usb-gp8psk-objs := gp8psk.o gp8psk-fe.o | |
| 11 | +dvb-usb-gp8psk-objs := gp8psk.o | |
| 12 | 12 | obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o |
| 13 | 13 | |
| 14 | 14 | dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | * see Documentation/dvb/README.dvb-usb for more information |
| 16 | 16 | */ |
| 17 | 17 | #include "gp8psk.h" |
| 18 | +#include "gp8psk-fe.h" | |
| 18 | 19 | |
| 19 | 20 | /* debug */ |
| 20 | 21 | static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; |
| @@ -28,34 +29,8 @@ struct gp8psk_state { · 7 unmodified lines | ||
| 28 | 29 | unsigned char data[80]; |
| 29 | 30 | }; |
| 30 | 31 | |
| 31 | −static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) | |
| 32 | −{ | |
| 33 | − return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6)); | |
| 34 | −} | |
| 35 | − | |
| 36 | −static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) | |
| 37 | −{ | |
| 38 | − return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1)); | |
| 39 | −} | |
| 40 | − | |
| 41 | −static void gp8psk_info(struct dvb_usb_device *d) | |
| 42 | −{ | |
| 43 | − u8 fpga_vers, fw_vers[6]; | |
| 44 | − | |
| 45 | − if (!gp8psk_get_fw_version(d, fw_vers)) | |
| 46 | − info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", | |
| 47 | − fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), | |
| 48 | − 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); | |
| 49 | − else | |
| 50 | − info("failed to get FW version"); | |
| 51 | − | |
| 52 | − if (!gp8psk_get_fpga_version(d, &fpga_vers)) | |
| 53 | − info("FPGA Version = %i", fpga_vers); | |
| 54 | − else | |
| 55 | − info("failed to get FPGA version"); | |
| 56 | −} | |
| 57 | − | |
| 58 | −int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) | |
| 32 | +static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, | |
| 33 | + u16 index, u8 *b, int blen) | |
| 59 | 34 | { |
| 60 | 35 | struct gp8psk_state *st = d->priv; |
| 61 | 36 | int ret = 0,try = 0; |
| @@ -93,7 +68,7 @@ int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 · 31 unmodified lines | ||
| 93 | 68 | return ret; |
| 94 | 69 | } |
| 95 | 70 | |
| 96 | −int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, | |
| 71 | +static int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, | |
| 97 | 72 | u16 index, u8 *b, int blen) |
| 98 | 73 | { |
| 99 | 74 | struct gp8psk_state *st = d->priv; |
| @@ -124,6 +99,34 @@ int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, · 24 unmodified lines | ||
| 124 | 99 | return ret; |
| 125 | 100 | } |
| 126 | 101 | |
| 102 | + | |
| 103 | +static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers) | |
| 104 | +{ | |
| 105 | + return gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6); | |
| 106 | +} | |
| 107 | + | |
| 108 | +static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers) | |
| 109 | +{ | |
| 110 | + return gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1); | |
| 111 | +} | |
| 112 | + | |
| 113 | +static void gp8psk_info(struct dvb_usb_device *d) | |
| 114 | +{ | |
| 115 | + u8 fpga_vers, fw_vers[6]; | |
| 116 | + | |
| 117 | + if (!gp8psk_get_fw_version(d, fw_vers)) | |
| 118 | + info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i", | |
| 119 | + fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers), | |
| 120 | + 2000 + fw_vers[5], fw_vers[4], fw_vers[3]); | |
| 121 | + else | |
| 122 | + info("failed to get FW version"); | |
| 123 | + | |
| 124 | + if (!gp8psk_get_fpga_version(d, &fpga_vers)) | |
| 125 | + info("FPGA Version = %i", fpga_vers); | |
| 126 | + else | |
| 127 | + info("failed to get FPGA version"); | |
| 128 | +} | |
| 129 | + | |
| 127 | 130 | static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) |
| 128 | 131 | { |
| 129 | 132 | int ret; |
| @@ -226,10 +229,13 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) · 96 unmodified lines | ||
| 226 | 229 | return 0; |
| 227 | 230 | } |
| 228 | 231 | |
| 229 | −int gp8psk_bcm4500_reload(struct dvb_usb_device *d) | |
| 232 | +static int gp8psk_bcm4500_reload(struct dvb_usb_device *d) | |
| 230 | 233 | { |
| 231 | 234 | u8 buf; |
| 232 | 235 | int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); |
| 236 | + | |
| 237 | + deb_xfer("reloading firmware\n"); | |
| 238 | + | |
| 233 | 239 | /* Turn off 8psk power */ |
| 234 | 240 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) |
| 235 | 241 | return -EINVAL; |
| @@ -248,9 +254,47 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) · 12 unmodified lines | ||
| 248 | 254 | return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); |
| 249 | 255 | } |
| 250 | 256 | |
| 257 | +/* Callbacks for gp8psk-fe.c */ | |
| 258 | + | |
| 259 | +static int gp8psk_fe_in(void *priv, u8 req, u16 value, | |
| 260 | + u16 index, u8 *b, int blen) | |
| 261 | +{ | |
| 262 | + struct dvb_usb_device *d = priv; | |
| 263 | + | |
| 264 | + return gp8psk_usb_in_op(d, req, value, index, b, blen); | |
| 265 | +} | |
| 266 | + | |
| 267 | +static int gp8psk_fe_out(void *priv, u8 req, u16 value, | |
| 268 | + u16 index, u8 *b, int blen) | |
| 269 | +{ | |
| 270 | + struct dvb_usb_device *d = priv; | |
| 271 | + | |
| 272 | + return gp8psk_usb_out_op(d, req, value, index, b, blen); | |
| 273 | +} | |
| 274 | + | |
| 275 | +static int gp8psk_fe_reload(void *priv) | |
| 276 | +{ | |
| 277 | + struct dvb_usb_device *d = priv; | |
| 278 | + | |
| 279 | + return gp8psk_bcm4500_reload(d); | |
| 280 | +} | |
| 281 | + | |
| 282 | +const struct gp8psk_fe_ops gp8psk_fe_ops = { | |
| 283 | + .in = gp8psk_fe_in, | |
| 284 | + .out = gp8psk_fe_out, | |
| 285 | + .reload = gp8psk_fe_reload, | |
| 286 | +}; | |
| 287 | + | |
| 251 | 288 | static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) |
| 252 | 289 | { |
| 253 | − adap->fe_adap[0].fe = gp8psk_fe_attach(adap->dev); | |
| 290 | + struct dvb_usb_device *d = adap->dev; | |
| 291 | + int id = le16_to_cpu(d->udev->descriptor.idProduct); | |
| 292 | + int is_rev1; | |
| 293 | + | |
| 294 | + is_rev1 = (id == USB_PID_GENPIX_8PSK_REV_1_WARM) ? true : false; | |
| 295 | + | |
| 296 | + adap->fe_adap[0].fe = dvb_attach(gp8psk_fe_attach, | |
| 297 | + &gp8psk_fe_ops, d, is_rev1); | |
| 254 | 298 | return 0; |
| 255 | 299 | } |
| 256 | 300 | |
| @@ -24,58 +24,6 @@ extern int dvb_usb_gp8psk_debug; · 23 unmodified lines | ||
| 24 | 24 | #define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) |
| 25 | 25 | #define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) |
| 26 | 26 | #define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) |
| 27 | −#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) | |
| 28 | − | |
| 29 | −/* Twinhan Vendor requests */ | |
| 30 | −#define TH_COMMAND_IN 0xC0 | |
| 31 | −#define TH_COMMAND_OUT 0xC1 | |
| 32 | − | |
| 33 | −/* gp8psk commands */ | |
| 34 | − | |
| 35 | −#define GET_8PSK_CONFIG 0x80 /* in */ | |
| 36 | −#define SET_8PSK_CONFIG 0x81 | |
| 37 | −#define I2C_WRITE 0x83 | |
| 38 | −#define I2C_READ 0x84 | |
| 39 | −#define ARM_TRANSFER 0x85 | |
| 40 | −#define TUNE_8PSK 0x86 | |
| 41 | −#define GET_SIGNAL_STRENGTH 0x87 /* in */ | |
| 42 | −#define LOAD_BCM4500 0x88 | |
| 43 | −#define BOOT_8PSK 0x89 /* in */ | |
| 44 | −#define START_INTERSIL 0x8A /* in */ | |
| 45 | −#define SET_LNB_VOLTAGE 0x8B | |
| 46 | −#define SET_22KHZ_TONE 0x8C | |
| 47 | −#define SEND_DISEQC_COMMAND 0x8D | |
| 48 | −#define SET_DVB_MODE 0x8E | |
| 49 | −#define SET_DN_SWITCH 0x8F | |
| 50 | −#define GET_SIGNAL_LOCK 0x90 /* in */ | |
| 51 | −#define GET_FW_VERS 0x92 | |
| 52 | −#define GET_SERIAL_NUMBER 0x93 /* in */ | |
| 53 | −#define USE_EXTRA_VOLT 0x94 | |
| 54 | −#define GET_FPGA_VERS 0x95 | |
| 55 | −#define CW3K_INIT 0x9d | |
| 56 | − | |
| 57 | −/* PSK_configuration bits */ | |
| 58 | −#define bm8pskStarted 0x01 | |
| 59 | −#define bm8pskFW_Loaded 0x02 | |
| 60 | −#define bmIntersilOn 0x04 | |
| 61 | −#define bmDVBmode 0x08 | |
| 62 | −#define bm22kHz 0x10 | |
| 63 | −#define bmSEL18V 0x20 | |
| 64 | −#define bmDCtuned 0x40 | |
| 65 | −#define bmArmed 0x80 | |
| 66 | − | |
| 67 | −/* Satellite modulation modes */ | |
| 68 | −#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ | |
| 69 | −#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ | |
| 70 | −#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ | |
| 71 | −#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ | |
| 72 | − | |
| 73 | −#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ | |
| 74 | −#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ | |
| 75 | −#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ | |
| 76 | −#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ | |
| 77 | −#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ | |
| 78 | −#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ | |
| 79 | 27 | |
| 80 | 28 | #define GET_USB_SPEED 0x07 |
| 81 | 29 | |
| @@ -86,15 +34,4 @@ extern int dvb_usb_gp8psk_debug; · 4 unmodified lines | ||
| 86 | 34 | #define PRODUCT_STRING_READ 0x0D |
| 87 | 35 | #define FW_BCD_VERSION_READ 0x14 |
| 88 | 36 | |
| 89 | −/* firmware revision id's */ | |
| 90 | −#define GP8PSK_FW_REV1 0x020604 | |
| 91 | −#define GP8PSK_FW_REV2 0x020704 | |
| 92 | −#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0]) | |
| 93 | − | |
| 94 | −extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); | |
| 95 | −extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); | |
| 96 | −extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, | |
| 97 | − u16 index, u8 *b, int blen); | |
| 98 | −extern int gp8psk_bcm4500_reload(struct dvb_usb_device *d); | |
| 99 | − | |
| 100 | 37 | #endif |