diff options
| author | Mauro Carvalho Chehab <mchehab@s-opensource.com> | 2016-11-12 09:46:28 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-11-13 13:02:22 -0500 |
| commit | 7a0786c19d65bd4502b4a53aec9ef75e18192a00 (patch) | |
| tree | 4674cd6fdcec0c7e5a77844694fbf30498894bf0 | |
| parent | 1596c387e970cb680d4031fbe4d6eb2c2a4ddb63 (diff) | |
gp8psk: Fix DVB frontend attach
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!"
Reported-by: Derek <user.vdr@gmail.com>
Tested-by: Derek <user.vdr@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | drivers/media/dvb-frontends/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/media/dvb-frontends/Makefile | 1 | ||||
| -rw-r--r-- | drivers/media/dvb-frontends/gp8psk-fe.c (renamed from drivers/media/usb/dvb-usb/gp8psk-fe.c) | 139 | ||||
| -rw-r--r-- | drivers/media/dvb-frontends/gp8psk-fe.h | 82 | ||||
| -rw-r--r-- | drivers/media/usb/dvb-usb/Makefile | 2 | ||||
| -rw-r--r-- | drivers/media/usb/dvb-usb/gp8psk.c | 106 | ||||
| -rw-r--r-- | drivers/media/usb/dvb-usb/gp8psk.h | 63 |
7 files changed, 246 insertions, 152 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 012225587c25..b71b747ee0ba 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig | |||
| @@ -513,6 +513,11 @@ config DVB_AS102_FE | |||
| 513 | depends on DVB_CORE | 513 | depends on DVB_CORE |
| 514 | default DVB_AS102 | 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 | comment "DVB-C (cable) frontends" | 521 | comment "DVB-C (cable) frontends" |
| 517 | depends on DVB_CORE | 522 | depends on DVB_CORE |
| 518 | 523 | ||
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index e90165ad361b..93921a4eaa27 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile | |||
| @@ -121,6 +121,7 @@ obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o | |||
| 121 | obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o | 121 | obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o |
| 122 | obj-$(CONFIG_DVB_AF9033) += af9033.o | 122 | obj-$(CONFIG_DVB_AF9033) += af9033.o |
| 123 | obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o | 123 | obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o |
| 124 | obj-$(CONFIG_DVB_GP8PSK_FE) += gp8psk-fe.o | ||
| 124 | obj-$(CONFIG_DVB_TC90522) += tc90522.o | 125 | obj-$(CONFIG_DVB_TC90522) += tc90522.o |
| 125 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o | 126 | obj-$(CONFIG_DVB_HORUS3A) += horus3a.o |
| 126 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o | 127 | obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o |
diff --git a/drivers/media/usb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb-frontends/gp8psk-fe.c index db6eb79cde07..be19afeed7a9 100644 --- a/drivers/media/usb/dvb-usb/gp8psk-fe.c +++ b/drivers/media/dvb-frontends/gp8psk-fe.c | |||
| @@ -14,11 +14,27 @@ | |||
| 14 | * | 14 | * |
| 15 | * see Documentation/dvb/README.dvb-usb for more information | 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 | struct gp8psk_fe_state { | 33 | struct gp8psk_fe_state { |
| 20 | struct dvb_frontend fe; | 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 | u8 lock; | 38 | u8 lock; |
| 23 | u16 snr; | 39 | u16 snr; |
| 24 | unsigned long next_status_check; | 40 | unsigned long next_status_check; |
| @@ -29,22 +45,24 @@ static int gp8psk_tuned_to_DCII(struct dvb_frontend *fe) | |||
| 29 | { | 45 | { |
| 30 | struct gp8psk_fe_state *st = fe->demodulator_priv; | 46 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 31 | u8 status; | 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 | return status & bmDCtuned; | 50 | return status & bmDCtuned; |
| 34 | } | 51 | } |
| 35 | 52 | ||
| 36 | static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) | 53 | static int gp8psk_set_tuner_mode(struct dvb_frontend *fe, int mode) |
| 37 | { | 54 | { |
| 38 | struct gp8psk_fe_state *state = fe->demodulator_priv; | 55 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 39 | return gp8psk_usb_out_op(state->d, SET_8PSK_CONFIG, mode, 0, NULL, 0); | 56 | |
| 57 | return st->ops->out(st->priv, SET_8PSK_CONFIG, mode, 0, NULL, 0); | ||
| 40 | } | 58 | } |
| 41 | 59 | ||
| 42 | static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) | 60 | static int gp8psk_fe_update_status(struct gp8psk_fe_state *st) |
| 43 | { | 61 | { |
| 44 | u8 buf[6]; | 62 | u8 buf[6]; |
| 45 | if (time_after(jiffies,st->next_status_check)) { | 63 | if (time_after(jiffies,st->next_status_check)) { |
| 46 | gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0,0,&st->lock,1); | 64 | st->ops->in(st->priv, GET_SIGNAL_LOCK, 0, 0, &st->lock, 1); |
| 47 | gp8psk_usb_in_op(st->d, GET_SIGNAL_STRENGTH, 0,0,buf,6); | 65 | st->ops->in(st->priv, GET_SIGNAL_STRENGTH, 0, 0, buf, 6); |
| 48 | st->snr = (buf[1]) << 8 | buf[0]; | 66 | st->snr = (buf[1]) << 8 | buf[0]; |
| 49 | st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000; | 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 | |||
| 116 | 134 | ||
| 117 | static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) | 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 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | 138 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
| 121 | u8 cmd[10]; | 139 | u8 cmd[10]; |
| 122 | u32 freq = c->frequency * 1000; | 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 | cmd[4] = freq & 0xff; | 144 | cmd[4] = freq & 0xff; |
| 128 | cmd[5] = (freq >> 8) & 0xff; | 145 | cmd[5] = (freq >> 8) & 0xff; |
| @@ -136,21 +153,21 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) | |||
| 136 | switch (c->delivery_system) { | 153 | switch (c->delivery_system) { |
| 137 | case SYS_DVBS: | 154 | case SYS_DVBS: |
| 138 | if (c->modulation != QPSK) { | 155 | if (c->modulation != QPSK) { |
| 139 | deb_fe("%s: unsupported modulation selected (%d)\n", | 156 | dprintk("%s: unsupported modulation selected (%d)\n", |
| 140 | __func__, c->modulation); | 157 | __func__, c->modulation); |
| 141 | return -EOPNOTSUPP; | 158 | return -EOPNOTSUPP; |
| 142 | } | 159 | } |
| 143 | c->fec_inner = FEC_AUTO; | 160 | c->fec_inner = FEC_AUTO; |
| 144 | break; | 161 | break; |
| 145 | case SYS_DVBS2: /* kept for backwards compatibility */ | 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 | break; | 164 | break; |
| 148 | case SYS_TURBO: | 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 | break; | 167 | break; |
| 151 | 168 | ||
| 152 | default: | 169 | default: |
| 153 | deb_fe("%s: unsupported delivery system selected (%d)\n", | 170 | dprintk("%s: unsupported delivery system selected (%d)\n", |
| 154 | __func__, c->delivery_system); | 171 | __func__, c->delivery_system); |
| 155 | return -EOPNOTSUPP; | 172 | return -EOPNOTSUPP; |
| 156 | } | 173 | } |
| @@ -161,9 +178,9 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) | |||
| 161 | cmd[3] = (c->symbol_rate >> 24) & 0xff; | 178 | cmd[3] = (c->symbol_rate >> 24) & 0xff; |
| 162 | switch (c->modulation) { | 179 | switch (c->modulation) { |
| 163 | case QPSK: | 180 | case QPSK: |
| 164 | if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM) | 181 | if (st->is_rev1) |
| 165 | if (gp8psk_tuned_to_DCII(fe)) | 182 | if (gp8psk_tuned_to_DCII(fe)) |
| 166 | gp8psk_bcm4500_reload(state->d); | 183 | st->ops->reload(st->priv); |
| 167 | switch (c->fec_inner) { | 184 | switch (c->fec_inner) { |
| 168 | case FEC_1_2: | 185 | case FEC_1_2: |
| 169 | cmd[9] = 0; break; | 186 | cmd[9] = 0; break; |
| @@ -207,18 +224,18 @@ static int gp8psk_fe_set_frontend(struct dvb_frontend *fe) | |||
| 207 | cmd[9] = 0; | 224 | cmd[9] = 0; |
| 208 | break; | 225 | break; |
| 209 | default: /* Unknown modulation */ | 226 | default: /* Unknown modulation */ |
| 210 | deb_fe("%s: unsupported modulation selected (%d)\n", | 227 | dprintk("%s: unsupported modulation selected (%d)\n", |
| 211 | __func__, c->modulation); | 228 | __func__, c->modulation); |
| 212 | return -EOPNOTSUPP; | 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 | gp8psk_set_tuner_mode(fe, 0); | 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; | 236 | st->lock = 0; |
| 220 | state->next_status_check = jiffies; | 237 | st->next_status_check = jiffies; |
| 221 | state->status_check_interval = 200; | 238 | st->status_check_interval = 200; |
| 222 | 239 | ||
| 223 | return 0; | 240 | return 0; |
| 224 | } | 241 | } |
| @@ -228,9 +245,9 @@ static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, | |||
| 228 | { | 245 | { |
| 229 | struct gp8psk_fe_state *st = fe->demodulator_priv; | 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 | m->msg, m->msg_len)) { | 251 | m->msg, m->msg_len)) { |
| 235 | return -EINVAL; | 252 | return -EINVAL; |
| 236 | } | 253 | } |
| @@ -243,12 +260,12 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe, | |||
| 243 | struct gp8psk_fe_state *st = fe->demodulator_priv; | 260 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 244 | u8 cmd; | 261 | u8 cmd; |
| 245 | 262 | ||
| 246 | deb_fe("%s\n",__func__); | 263 | dprintk("%s\n", __func__); |
| 247 | 264 | ||
| 248 | /* These commands are certainly wrong */ | 265 | /* These commands are certainly wrong */ |
| 249 | cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; | 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 | &cmd, 0)) { | 269 | &cmd, 0)) { |
| 253 | return -EINVAL; | 270 | return -EINVAL; |
| 254 | } | 271 | } |
| @@ -258,10 +275,10 @@ static int gp8psk_fe_send_diseqc_burst(struct dvb_frontend *fe, | |||
| 258 | static int gp8psk_fe_set_tone(struct dvb_frontend *fe, | 275 | static int gp8psk_fe_set_tone(struct dvb_frontend *fe, |
| 259 | enum fe_sec_tone_mode tone) | 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, | 280 | if (st->ops->out(st->priv, SET_22KHZ_TONE, |
| 264 | (tone == SEC_TONE_ON), 0, NULL, 0)) { | 281 | (tone == SEC_TONE_ON), 0, NULL, 0)) { |
| 265 | return -EINVAL; | 282 | return -EINVAL; |
| 266 | } | 283 | } |
| 267 | return 0; | 284 | return 0; |
| @@ -270,9 +287,9 @@ static int gp8psk_fe_set_tone(struct dvb_frontend *fe, | |||
| 270 | static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, | 287 | static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, |
| 271 | enum fe_sec_voltage voltage) | 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 | voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { | 293 | voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { |
| 277 | return -EINVAL; | 294 | return -EINVAL; |
| 278 | } | 295 | } |
| @@ -281,52 +298,60 @@ static int gp8psk_fe_set_voltage(struct dvb_frontend *fe, | |||
| 281 | 298 | ||
| 282 | static int gp8psk_fe_enable_high_lnb_voltage(struct dvb_frontend* fe, long onoff) | 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; | 301 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 285 | return gp8psk_usb_out_op(state->d, USE_EXTRA_VOLT, onoff, 0,NULL,0); | 302 | |
| 303 | return st->ops->out(st->priv, USE_EXTRA_VOLT, onoff, 0, NULL, 0); | ||
| 286 | } | 304 | } |
| 287 | 305 | ||
| 288 | static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) | 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 | u8 cmd = sw_cmd & 0x7f; | 309 | u8 cmd = sw_cmd & 0x7f; |
| 292 | 310 | ||
| 293 | if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, | 311 | if (st->ops->out(st->priv, SET_DN_SWITCH, cmd, 0, NULL, 0)) |
| 294 | NULL, 0)) { | ||
| 295 | return -EINVAL; | 312 | return -EINVAL; |
| 296 | } | 313 | |
| 297 | if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), | 314 | if (st->ops->out(st->priv, SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), |
| 298 | 0, NULL, 0)) { | 315 | 0, NULL, 0)) |
| 299 | return -EINVAL; | 316 | return -EINVAL; |
| 300 | } | ||
| 301 | 317 | ||
| 302 | return 0; | 318 | return 0; |
| 303 | } | 319 | } |
| 304 | 320 | ||
| 305 | static void gp8psk_fe_release(struct dvb_frontend* fe) | 321 | static void gp8psk_fe_release(struct dvb_frontend* fe) |
| 306 | { | 322 | { |
| 307 | struct gp8psk_fe_state *state = fe->demodulator_priv; | 323 | struct gp8psk_fe_state *st = fe->demodulator_priv; |
| 308 | kfree(state); | 324 | |
| 325 | kfree(st); | ||
| 309 | } | 326 | } |
| 310 | 327 | ||
| 311 | static struct dvb_frontend_ops gp8psk_fe_ops; | 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); | 333 | struct gp8psk_fe_state *st; |
| 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 | } | ||
| 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 | static struct dvb_frontend_ops gp8psk_fe_ops = { | 356 | static struct dvb_frontend_ops gp8psk_fe_ops = { |
| 332 | .delsys = { SYS_DVBS }, | 357 | .delsys = { SYS_DVBS }, |
diff --git a/drivers/media/dvb-frontends/gp8psk-fe.h b/drivers/media/dvb-frontends/gp8psk-fe.h new file mode 100644 index 000000000000..6c7944b1ecd6 --- /dev/null +++ b/drivers/media/dvb-frontends/gp8psk-fe.h | |||
| @@ -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 | ||
diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index 2a7b5a963acf..3b3f32b426d1 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile | |||
| @@ -8,7 +8,7 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o | |||
| 8 | dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o | 8 | dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o |
| 9 | obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o | 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 | obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o | 12 | obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o |
| 13 | 13 | ||
| 14 | dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o | 14 | dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o |
diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index 2829e3082d15..993bb7a72985 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | * see Documentation/dvb/README.dvb-usb for more information | 15 | * see Documentation/dvb/README.dvb-usb for more information |
| 16 | */ | 16 | */ |
| 17 | #include "gp8psk.h" | 17 | #include "gp8psk.h" |
| 18 | #include "gp8psk-fe.h" | ||
| 18 | 19 | ||
| 19 | /* debug */ | 20 | /* debug */ |
| 20 | static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; | 21 | static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; |
| @@ -28,34 +29,8 @@ struct gp8psk_state { | |||
| 28 | unsigned char data[80]; | 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 | static int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, |
| 32 | { | 33 | u16 index, u8 *b, int blen) |
| 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) | ||
| 59 | { | 34 | { |
| 60 | struct gp8psk_state *st = d->priv; | 35 | struct gp8psk_state *st = d->priv; |
| 61 | int ret = 0,try = 0; | 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 | |||
| 93 | return ret; | 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 | u16 index, u8 *b, int blen) | 72 | u16 index, u8 *b, int blen) |
| 98 | { | 73 | { |
| 99 | struct gp8psk_state *st = d->priv; | 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, | |||
| 124 | return ret; | 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 | static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) | 130 | static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) |
| 128 | { | 131 | { |
| 129 | int ret; | 132 | int ret; |
| @@ -226,10 +229,13 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) | |||
| 226 | return 0; | 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 | u8 buf; | 234 | u8 buf; |
| 232 | int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); | 235 | int gp_product_id = le16_to_cpu(d->udev->descriptor.idProduct); |
| 236 | |||
| 237 | deb_xfer("reloading firmware\n"); | ||
| 238 | |||
| 233 | /* Turn off 8psk power */ | 239 | /* Turn off 8psk power */ |
| 234 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) | 240 | if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) |
| 235 | return -EINVAL; | 241 | return -EINVAL; |
| @@ -248,9 +254,47 @@ static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) | |||
| 248 | return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0); | 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 | static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap) | 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 | return 0; | 298 | return 0; |
| 255 | } | 299 | } |
| 256 | 300 | ||
diff --git a/drivers/media/usb/dvb-usb/gp8psk.h b/drivers/media/usb/dvb-usb/gp8psk.h index ed32b9da4843..d8975b866dee 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.h +++ b/drivers/media/usb/dvb-usb/gp8psk.h | |||
| @@ -24,58 +24,6 @@ extern int dvb_usb_gp8psk_debug; | |||
| 24 | #define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) | 24 | #define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) |
| 25 | #define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) | 25 | #define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) |
| 26 | #define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) | 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 | #define GET_USB_SPEED 0x07 | 28 | #define GET_USB_SPEED 0x07 |
| 81 | 29 | ||
| @@ -86,15 +34,4 @@ extern int dvb_usb_gp8psk_debug; | |||
| 86 | #define PRODUCT_STRING_READ 0x0D | 34 | #define PRODUCT_STRING_READ 0x0D |
| 87 | #define FW_BCD_VERSION_READ 0x14 | 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 | #endif | 37 | #endif |
