Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9404ef34 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville
Browse files

rt2x00: Driver requiring firmware should select crc algo



The driver should select what CRC algorithm is required
when performing a checksum on the firmware.

rt61pci & rt73usb require crc-itu-t
rt2800pci & rt2800usb require crc-ccitt

Legacy 2800pci/usb driver uses crc-itu-t + bit order reversion,
but that is just inefficient especially since the end result is
the same as a different algorithm which is also available as library. ;)

Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent adfdbb79
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ config RT2X00_LIB_USB
config RT2X00_LIB_FIRMWARE
	boolean
	depends on RT2X00_LIB
	select CRC_CCITT
	select CRC_ITU_T
	select FW_LOADER

+2 −0
Original line number Diff line number Diff line
@@ -551,6 +551,8 @@ enum rt2x00_flags {
	 * Driver features
	 */
	DRIVER_REQUIRE_FIRMWARE,
	DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T,
	DRIVER_REQUIRE_FIRMWARE_CCITT,
	DRIVER_REQUIRE_BEACON_GUARD,
	DRIVER_REQUIRE_ATIM_QUEUE,

+3 −5
Original line number Diff line number Diff line
@@ -1017,11 +1017,9 @@ int rt2x00lib_start(struct rt2x00_dev *rt2x00dev)
	 * If this is the first interface which is added,
	 * we should load the firmware now.
	 */
	if (test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags)) {
	retval = rt2x00lib_load_firmware(rt2x00dev);
	if (retval)
		return retval;
	}

	/*
	 * Initialize the device.
+32 −9
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
	Abstract: rt2x00 firmware loading routines.
 */

#include <linux/crc-ccitt.h>
#include <linux/crc-itu-t.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -37,7 +38,6 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
	char *fw_name;
	int retval;
	u16 crc;
	u16 tmp;

	/*
	 * Read correct firmware from harddisk.
@@ -64,17 +64,37 @@ static int rt2x00lib_request_firmware(struct rt2x00_dev *rt2x00dev)
	}

	/*
	 * Validate the firmware using 16 bit CRC.
	 * The last 2 bytes of the firmware are the CRC
	 * so substract those 2 bytes from the CRC checksum,
	 * and set those 2 bytes to 0 when calculating CRC.
	 * Perform crc validation on the firmware.
	 * The last 2 bytes in the firmware array are the crc checksum itself,
	 * this means that we should never pass those 2 bytes to the crc
	 * algorithm.
	 */
	if (test_bit(DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T, &rt2x00dev->flags)) {
		/*
		 * Use the crc itu-t algorithm.
		 * Use 0 for the last 2 bytes to complete the checksum.
		 */
	tmp = 0;
		crc = crc_itu_t(0, fw->data, fw->size - 2);
	crc = crc_itu_t(crc, (u8 *)&tmp, 2);
		crc = crc_itu_t_byte(crc, 0);
		crc = crc_itu_t_byte(crc, 0);
	} else if (test_bit(DRIVER_REQUIRE_FIRMWARE_CCITT, &rt2x00dev->flags)) {
		/*
		 * Use the crc ccitt algorithm.
		 * This will return the same value as the legacy driver which
		 * used bit ordering reversion on the both the firmware bytes
		 * before input input as well as on the final output.
		 * Obviously using crc ccitt directly is much more efficient.
		 */
		crc = crc_ccitt(~0, fw->data, fw->size - 2);
	} else {
		ERROR(rt2x00dev, "No checksum algorithm selected "
		      "for firmware validation.\n");
		retval = -ENOENT;
		goto exit;
	}

	if (crc != (fw->data[fw->size - 2] << 8 | fw->data[fw->size - 1])) {
		ERROR(rt2x00dev, "Firmware CRC error.\n");
		ERROR(rt2x00dev, "Firmware checksum error.\n");
		retval = -ENOENT;
		goto exit;
	}
@@ -96,6 +116,9 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
	int retval;

	if (!test_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags))
		return 0;

	if (!rt2x00dev->fw) {
		retval = rt2x00lib_request_firmware(rt2x00dev);
		if (retval)
+2 −1
Original line number Diff line number Diff line
@@ -2258,9 +2258,10 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev)
	rt61pci_probe_hw_mode(rt2x00dev);

	/*
	 * This device requires firmware
	 * This device requires firmware.
	 */
	__set_bit(DRIVER_REQUIRE_FIRMWARE, &rt2x00dev->flags);
	__set_bit(DRIVER_REQUIRE_FIRMWARE_CRC_ITU_T, &rt2x00dev->flags);

	/*
	 * Set the rssi offset.
Loading