1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
From: Ben Hutchings <ben@decadent.org.uk>
Date: Mon, 24 Aug 2009 23:19:58 +0100
Subject: af9005: Use request_firmware() to load register init script
Forwarded: no
Read the register init script from the Windows driver. This is sick
but should avoid the potential copyright infringement in distributing
a version of the script which is directly derived from the driver.
---
drivers/media/dvb/dvb-usb/Kconfig | 2 +-
drivers/media/dvb/dvb-usb/af9005-fe.c | 66 ++++++++++++++++++++++++++------
2 files changed, 54 insertions(+), 14 deletions(-)
Index: linux/drivers/media/usb/dvb-usb/Kconfig
===================================================================
--- linux.orig/drivers/media/usb/dvb-usb/Kconfig
+++ linux/drivers/media/usb/dvb-usb/Kconfig
@@ -246,10 +246,10 @@ config DVB_USB_OPERA1
config DVB_USB_AF9005
tristate "Afatech AF9005 DVB-T USB1.1 support"
- depends on BROKEN
depends on DVB_USB
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
+ select FW_LOADER
help
Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
and the TerraTec Cinergy T USB XE (Rev.1)
Index: linux/drivers/media/usb/dvb-usb/af9005-fe.c
===================================================================
--- linux.orig/drivers/media/usb/dvb-usb/af9005-fe.c
+++ linux/drivers/media/usb/dvb-usb/af9005-fe.c
@@ -18,10 +18,26 @@
* see Documentation/media/dvb-drivers/dvb-usb.rst for more information
*/
#include "af9005.h"
-#include "af9005-script.h"
#include "mt2060.h"
#include "qt1010.h"
#include <asm/div64.h>
+#include <linux/firmware.h>
+
+/* Register initialisation script to be extracted from the Windows driver */
+
+typedef struct {
+ __le16 reg;
+ u8 pos;
+ u8 len;
+ u8 val;
+ u8 pad;
+} __packed RegDesc;
+
+#define WIN_DRV_NAME "AF05BDA.sys"
+#define WIN_DRV_VERSION "6.3.2.1"
+#define WIN_DRV_SIZE 133504
+#define WIN_DRV_SCRIPT_OFFSET 88316
+#define WIN_DRV_SCRIPT_SIZE 1110
struct af9005_fe_state {
struct dvb_usb_device *d;
@@ -813,6 +829,8 @@ static int af9005_fe_init(struct dvb_fro
{
struct af9005_fe_state *state = fe->demodulator_priv;
struct dvb_usb_adapter *adap = fe->dvb->priv;
+ const struct firmware *fw;
+ const RegDesc *script;
int ret, i, scriptlen;
u8 temp, temp0 = 0, temp1 = 0, temp2 = 0;
u8 buf[2];
@@ -965,37 +983,55 @@ static int af9005_fe_init(struct dvb_fro
if ((ret = af9005_write_ofdm_register(state->d, 0xaefb, 0x01)))
return ret;
- /* load init script */
- deb_info("load init script\n");
- scriptlen = sizeof(script) / sizeof(RegDesc);
+ /* load and validate init script */
+ deb_info("load init script from Windows driver\n");
+ ret = request_firmware(&fw, WIN_DRV_NAME, &state->d->udev->dev);
+ if (ret)
+ return ret;
+ BUILD_BUG_ON(sizeof(RegDesc) != 6);
+ if (fw->size != WIN_DRV_SIZE ||
+ memcmp(fw->data + WIN_DRV_SCRIPT_OFFSET,
+ "\x80\xa1\x00\x08\x0a\x00", 6) ||
+ memcmp(fw->data + WIN_DRV_SCRIPT_OFFSET + WIN_DRV_SCRIPT_SIZE - 6,
+ "\x49\xa3\x00\x06\x02\x00", 6)) {
+ err("%s is invalid - should be version %s, size %u bytes\n",
+ WIN_DRV_NAME, WIN_DRV_VERSION, WIN_DRV_SIZE);
+ ret = -EINVAL;
+ goto fail_release;
+ }
+
+ script = (const RegDesc *)(fw->data + WIN_DRV_SCRIPT_OFFSET);
+ scriptlen = WIN_DRV_SCRIPT_SIZE / sizeof(RegDesc);
for (i = 0; i < scriptlen; i++) {
+ u16 reg = le16_to_cpu(script[i].reg);
if ((ret =
- af9005_write_register_bits(state->d, script[i].reg,
+ af9005_write_register_bits(state->d, reg,
script[i].pos,
script[i].len, script[i].val)))
- return ret;
+ goto fail_release;
/* save 3 bytes of original fcw */
- if (script[i].reg == 0xae18)
+ if (reg == 0xae18)
temp2 = script[i].val;
- if (script[i].reg == 0xae19)
+ if (reg == 0xae19)
temp1 = script[i].val;
- if (script[i].reg == 0xae1a)
+ if (reg == 0xae1a)
temp0 = script[i].val;
/* save original unplug threshold */
- if (script[i].reg == xd_p_reg_unplug_th)
+ if (reg == xd_p_reg_unplug_th)
state->original_if_unplug_th = script[i].val;
- if (script[i].reg == xd_p_reg_unplug_rf_gain_th)
+ if (reg == xd_p_reg_unplug_rf_gain_th)
state->original_rf_unplug_th = script[i].val;
- if (script[i].reg == xd_p_reg_unplug_dtop_if_gain_th)
+ if (reg == xd_p_reg_unplug_dtop_if_gain_th)
state->original_dtop_if_unplug_th = script[i].val;
- if (script[i].reg == xd_p_reg_unplug_dtop_rf_gain_th)
+ if (reg == xd_p_reg_unplug_dtop_rf_gain_th)
state->original_dtop_rf_unplug_th = script[i].val;
}
state->original_fcw =
((u32) temp2 << 16) + ((u32) temp1 << 8) + (u32) temp0;
+ release_firmware(fw);
/* save original TOPs */
deb_info("save original TOPs\n");
@@ -1075,6 +1111,10 @@ static int af9005_fe_init(struct dvb_fro
deb_info("profit!\n");
return 0;
+
+fail_release:
+ release_firmware(fw);
+ return ret;
}
static int af9005_fe_sleep(struct dvb_frontend *fe)
|