Package: linux / 3.2.78-1

features/all/drivers-media-dvb-usb-af9005-request_firmware.patch Patch series | download
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
150
151
152
From 0b8d838ecaa0235000347c084d192aa30b76ae70 Mon Sep 17 00:00:00 2001
From: Ben Hutchings <ben@decadent.org.uk>
Date: Mon, 24 Aug 2009 23:19:58 +0100
Subject: [PATCH] af9005: Use request_firmware() to load register init script

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(-)

diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 868e1cb..1c3d56d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -238,10 +238,10 @@ config DVB_USB_OPERA1
 
 config DVB_USB_AF9005
 	tristate "Afatech AF9005 DVB-T USB1.1 support"
-	depends on BROKEN
 	depends on DVB_USB && EXPERIMENTAL
 	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+	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)
diff --git a/drivers/media/dvb/dvb-usb/af9005-fe.c b/drivers/media/dvb/dvb-usb/af9005-fe.c
index 199ece0..bcc26c8 100644
--- a/drivers/media/dvb/dvb-usb/af9005-fe.c
+++ b/drivers/media/dvb/dvb-usb/af9005-fe.c
@@ -22,10 +22,26 @@
  * see Documentation/dvb/README.dvb-usb 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;
@@ -818,6 +834,8 @@ static int af9005_fe_init(struct dvb_frontend *fe)
 {
 	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];
@@ -969,37 +987,55 @@ static int af9005_fe_init(struct dvb_frontend *fe)
 	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");
@@ -1079,6 +1115,10 @@ static int af9005_fe_init(struct dvb_frontend *fe)
 
 	deb_info("profit!\n");
 	return 0;
+
+fail_release:
+	release_firmware(fw);
+	return ret;
 }
 
 static int af9005_fe_sleep(struct dvb_frontend *fe)
-- 
1.6.3.3