af9005: Use request_firmware() to load register init script
authorBen Hutchings <ben@decadent.org.uk>
Mon, 24 Aug 2009 22:19:58 +0000 (23:19 +0100)
committerSalvatore Bonaccorso <carnil@debian.org>
Mon, 8 May 2023 20:16:50 +0000 (21:16 +0100)
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.

Gbp-Pq: Topic features/all
Gbp-Pq: Name drivers-media-dvb-usb-af9005-request_firmware.patch

drivers/media/usb/dvb-usb/Kconfig
drivers/media/usb/dvb-usb/af9005-fe.c

index 3a8aacacc59253451015da6fd2705fc210b7dd8c..c5189847aefdf66f48e4a6b6bf0a74ae52b41059 100644 (file)
@@ -35,10 +35,10 @@ config DVB_USB_A800
 
 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 9d6fa0556d7b5b1c20ce51928fa984a2915af2ac..0210097f8c9af1bbbd5c6dafd134d2de092b58bc 100644 (file)
@@ -9,10 +9,26 @@
  * see Documentation/driver-api/media/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;
@@ -804,6 +820,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];
@@ -956,37 +974,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");
@@ -1066,6 +1102,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)