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

Commit fcb2c0d6 authored by John W. Linville's avatar John W. Linville
Browse files

Merge branch 'master' of...

parents 96b2e73c a715c7dd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
* STMicroelectronics SAS. ST21NFCA NFC Controller

Required properties:
- compatible: Should be "st,st21nfca-i2c".
- compatible: Should be "st,st21nfca_i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
+154 −1
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_WRONG_SCO_MTU	0x40
#define BTUSB_ATH3012		0x80
#define BTUSB_INTEL		0x100
#define BTUSB_BCM_PATCHRAM	0x200

static const struct usb_device_id btusb_table[] = {
	/* Generic Bluetooth USB device */
@@ -111,7 +112,8 @@ static const struct usb_device_id btusb_table[] = {
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },

	/* Broadcom devices with vendor specific id */
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
	{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
	  .driver_info = BTUSB_BCM_PATCHRAM },

	/* Belkin F8065bf - Broadcom based */
	{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
@@ -1381,6 +1383,154 @@ exit_mfg_deactivate:
	return 0;
}

static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
{
	struct btusb_data *data = hci_get_drvdata(hdev);
	struct usb_device *udev = data->udev;
	char fw_name[64];
	const struct firmware *fw;
	const u8 *fw_ptr;
	size_t fw_size;
	const struct hci_command_hdr *cmd;
	const u8 *cmd_param;
	u16 opcode;
	struct sk_buff *skb;
	struct hci_rp_read_local_version *ver;
	long ret;

	snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd",
		 udev->product ? udev->product : "BCM",
		 le16_to_cpu(udev->descriptor.idVendor),
		 le16_to_cpu(udev->descriptor.idProduct));

	ret = request_firmware(&fw, fw_name, &hdev->dev);
	if (ret < 0) {
		BT_INFO("%s: BCM: patch %s not found", hdev->name,
			fw_name);
		return 0;
	}

	/* Reset */
	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
		goto done;
	}
	kfree_skb(skb);

	/* Read Local Version Info */
	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
			hdev->name, ret);
		goto done;
	}

	if (skb->len != sizeof(*ver)) {
		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
			hdev->name);
		kfree_skb(skb);
		ret = -EIO;
		goto done;
	}

	ver = (struct hci_rp_read_local_version *) skb->data;
	BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
		"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
		ver->lmp_ver, ver->lmp_subver);
	kfree_skb(skb);

	/* Start Download */
	skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
			hdev->name, ret);
		goto reset_fw;
	}
	kfree_skb(skb);

	/* 50 msec delay after Download Minidrv completes */
	msleep(50);

	fw_ptr = fw->data;
	fw_size = fw->size;

	while (fw_size >= sizeof(*cmd)) {
		cmd = (struct hci_command_hdr *) fw_ptr;
		fw_ptr += sizeof(*cmd);
		fw_size -= sizeof(*cmd);

		if (fw_size < cmd->plen) {
			BT_ERR("%s: BCM: patch %s is corrupted",
				hdev->name, fw_name);
			ret = -EINVAL;
			goto reset_fw;
		}

		cmd_param = fw_ptr;
		fw_ptr += cmd->plen;
		fw_size -= cmd->plen;

		opcode = le16_to_cpu(cmd->opcode);

		skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
				     HCI_INIT_TIMEOUT);
		if (IS_ERR(skb)) {
			ret = PTR_ERR(skb);
			BT_ERR("%s: BCM: patch command %04x failed (%ld)",
				hdev->name, opcode, ret);
			goto reset_fw;
		}
		kfree_skb(skb);
	}

	/* 250 msec delay after Launch Ram completes */
	msleep(250);

reset_fw:
	/* Reset */
	skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
		goto done;
	}
	kfree_skb(skb);

	/* Read Local Version Info */
	skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
			     HCI_INIT_TIMEOUT);
	if (IS_ERR(skb)) {
		ret = PTR_ERR(skb);
		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)",
			hdev->name, ret);
		goto done;
	}

	if (skb->len != sizeof(*ver)) {
		BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch",
			hdev->name);
		kfree_skb(skb);
		ret = -EIO;
		goto done;
	}

	ver = (struct hci_rp_read_local_version *) skb->data;
	BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x "
		"lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev,
		ver->lmp_ver, ver->lmp_subver);
	kfree_skb(skb);

done:
	release_firmware(fw);

	return ret;
}

static int btusb_probe(struct usb_interface *intf,
				const struct usb_device_id *id)
{
@@ -1486,6 +1636,9 @@ static int btusb_probe(struct usb_interface *intf,
	if (id->driver_info & BTUSB_BCM92035)
		hdev->setup = btusb_setup_bcm92035;

	if (id->driver_info & BTUSB_BCM_PATCHRAM)
		hdev->setup = btusb_setup_bcm_patchram;

	if (id->driver_info & BTUSB_INTEL)
		hdev->setup = btusb_setup_intel;

+95 −32
Original line number Diff line number Diff line
@@ -365,15 +365,15 @@ static inline unsigned long at76_get_timeout(struct dfu_status *s)
static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
				int manifest_sync_timeout)
{
	u8 *block;
	struct dfu_status dfu_stat_buf;
	int ret = 0;
	int need_dfu_state = 1;
	int is_done = 0;
	u8 dfu_state = 0;
	u32 dfu_timeout = 0;
	int bsize = 0;
	int blockno = 0;
	struct dfu_status *dfu_stat_buf = NULL;
	u8 *dfu_state = NULL;
	u8 *block = NULL;

	at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
		 manifest_sync_timeout);
@@ -383,13 +383,28 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
		return -EINVAL;
	}

	dfu_stat_buf = kmalloc(sizeof(struct dfu_status), GFP_KERNEL);
	if (!dfu_stat_buf) {
		ret = -ENOMEM;
		goto exit;
	}

	block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
	if (!block)
		return -ENOMEM;
	if (!block) {
		ret = -ENOMEM;
		goto exit;
	}

	dfu_state = kmalloc(sizeof(u8), GFP_KERNEL);
	if (!dfu_state) {
		ret = -ENOMEM;
		goto exit;
	}
	*dfu_state = 0;

	do {
		if (need_dfu_state) {
			ret = at76_dfu_get_state(udev, &dfu_state);
			ret = at76_dfu_get_state(udev, dfu_state);
			if (ret < 0) {
				dev_err(&udev->dev,
					"cannot get DFU state: %d\n", ret);
@@ -398,13 +413,13 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
			need_dfu_state = 0;
		}

		switch (dfu_state) {
		switch (*dfu_state) {
		case STATE_DFU_DOWNLOAD_SYNC:
			at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
			ret = at76_dfu_get_status(udev, &dfu_stat_buf);
			ret = at76_dfu_get_status(udev, dfu_stat_buf);
			if (ret >= 0) {
				dfu_state = dfu_stat_buf.state;
				dfu_timeout = at76_get_timeout(&dfu_stat_buf);
				*dfu_state = dfu_stat_buf->state;
				dfu_timeout = at76_get_timeout(dfu_stat_buf);
				need_dfu_state = 0;
			} else
				dev_err(&udev->dev,
@@ -447,12 +462,12 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
		case STATE_DFU_MANIFEST_SYNC:
			at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");

			ret = at76_dfu_get_status(udev, &dfu_stat_buf);
			ret = at76_dfu_get_status(udev, dfu_stat_buf);
			if (ret < 0)
				break;

			dfu_state = dfu_stat_buf.state;
			dfu_timeout = at76_get_timeout(&dfu_stat_buf);
			*dfu_state = dfu_stat_buf->state;
			dfu_timeout = at76_get_timeout(dfu_stat_buf);
			need_dfu_state = 0;

			/* override the timeout from the status response,
@@ -484,14 +499,17 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
			break;

		default:
			at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
			at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", *dfu_state);
			ret = -EINVAL;
			break;
		}
	} while (!is_done && (ret >= 0));

exit:
	kfree(dfu_state);
	kfree(block);
	kfree(dfu_stat_buf);

	if (ret >= 0)
		ret = 0;

@@ -1277,6 +1295,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
			dev_err(&udev->dev,
				"loading %dth firmware block failed: %d\n",
				blockno, ret);
			ret = -EIO;
			goto exit;
		}
		buf += bsize;
@@ -2020,6 +2039,44 @@ static void at76_configure_filter(struct ieee80211_hw *hw,
	ieee80211_queue_work(hw, &priv->work_set_promisc);
}

static int at76_set_wep(struct at76_priv *priv)
{
	int ret = 0;
	struct mib_mac_wep *mib_data = &priv->mib_buf.data.wep_mib;

	priv->mib_buf.type = MIB_MAC_WEP;
	priv->mib_buf.size = sizeof(struct mib_mac_wep);
	priv->mib_buf.index = 0;

	memset(mib_data, 0, sizeof(*mib_data));

	if (priv->wep_enabled) {
		if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)
			mib_data->encryption_level = 2;
		else
			mib_data->encryption_level = 1;

		/* always exclude unencrypted if WEP is active */
		mib_data->exclude_unencrypted = 1;
	} else {
		mib_data->exclude_unencrypted = 0;
		mib_data->encryption_level = 0;
	}

	mib_data->privacy_invoked = priv->wep_enabled;
	mib_data->wep_default_key_id = priv->wep_key_id;
	memcpy(mib_data->wep_default_keyvalue, priv->wep_keys,
	       sizeof(priv->wep_keys));

	ret = at76_set_mib(priv, &priv->mib_buf);

	if (ret < 0)
		wiphy_err(priv->hw->wiphy,
			  "set_mib (wep) failed: %d\n", ret);

	return ret;
}

static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
			struct ieee80211_vif *vif, struct ieee80211_sta *sta,
			struct ieee80211_key_conf *key)
@@ -2062,7 +2119,7 @@ static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
			priv->wep_enabled = 1;
	}

	at76_startup_device(priv);
	at76_set_wep(priv);

	mutex_unlock(&priv->mtx);

@@ -2330,16 +2387,22 @@ static int at76_probe(struct usb_interface *interface,
	struct usb_device *udev;
	int op_mode;
	int need_ext_fw = 0;
	struct mib_fw_version fwv;
	struct mib_fw_version *fwv = NULL;
	int board_type = (int)id->driver_info;

	udev = usb_get_dev(interface_to_usbdev(interface));

	fwv = kmalloc(sizeof(*fwv), GFP_KERNEL);
	if (!fwv) {
		ret = -ENOMEM;
		goto exit;
	}

	/* Load firmware into kernel memory */
	fwe = at76_load_firmware(udev, board_type);
	if (!fwe) {
		ret = -ENOENT;
		goto error;
		goto exit;
	}

	op_mode = at76_get_op_mode(udev);
@@ -2353,7 +2416,7 @@ static int at76_probe(struct usb_interface *interface,
		dev_err(&interface->dev,
			"cannot handle a device in HW_CONFIG_MODE\n");
		ret = -EBUSY;
		goto error;
		goto exit;
	}

	if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
@@ -2366,10 +2429,10 @@ static int at76_probe(struct usb_interface *interface,
			dev_err(&interface->dev,
				"error %d downloading internal firmware\n",
				ret);
			goto error;
			goto exit;
		}
		usb_put_dev(udev);
		return ret;
		goto exit;
	}

	/* Internal firmware already inside the device.  Get firmware
@@ -2382,8 +2445,8 @@ static int at76_probe(struct usb_interface *interface,
	 * query the device for the fw version */
	if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
	    || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
		ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
		if (ret < 0 || (fwv.major | fwv.minor) == 0)
		ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
		if (ret < 0 || (fwv->major | fwv->minor) == 0)
			need_ext_fw = 1;
	} else
		/* No way to check firmware version, reload to be sure */
@@ -2394,36 +2457,36 @@ static int at76_probe(struct usb_interface *interface,
			   "downloading external firmware\n");

		ret = at76_load_external_fw(udev, fwe);
		if (ret)
			goto error;
		if (ret < 0)
			goto exit;

		/* Re-check firmware version */
		ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
		ret = at76_get_mib(udev, MIB_FW_VERSION, fwv, sizeof(*fwv));
		if (ret < 0) {
			dev_err(&interface->dev,
				"error %d getting firmware version\n", ret);
			goto error;
			goto exit;
		}
	}

	priv = at76_alloc_new_device(udev);
	if (!priv) {
		ret = -ENOMEM;
		goto error;
		goto exit;
	}

	usb_set_intfdata(interface, priv);

	memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
	memcpy(&priv->fw_version, fwv, sizeof(struct mib_fw_version));
	priv->board_type = board_type;

	ret = at76_init_new_device(priv, interface);
	if (ret < 0)
		at76_delete_device(priv);

	return ret;

error:
exit:
	kfree(fwv);
	if (ret < 0)
		usb_put_dev(udev);
	return ret;
}
+13 −12
Original line number Diff line number Diff line
@@ -219,18 +219,6 @@ struct at76_req_join {
	u8 reserved;
} __packed;

struct set_mib_buffer {
	u8 type;
	u8 size;
	u8 index;
	u8 reserved;
	union {
		u8 byte;
		__le16 word;
		u8 addr[ETH_ALEN];
	} data;
} __packed;

struct mib_local {
	u16 reserved0;
	u8 beacon_enable;
@@ -334,6 +322,19 @@ struct mib_mdomain {
	u8 channel_list[14];	/* 0 for invalid channels */
} __packed;

struct set_mib_buffer {
	u8 type;
	u8 size;
	u8 index;
	u8 reserved;
	union {
		u8 byte;
		__le16 word;
		u8 addr[ETH_ALEN];
		struct mib_mac_wep wep_mib;
	} data;
} __packed;

struct at76_fw_header {
	__le32 crc;		/* CRC32 of the whole image */
	__le32 board_type;	/* firmware compatibility code */
+2 −1
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
									\
		addr = host_interest_item_address(HI_ITEM(item));	\
		ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
		if (!ret)						\
			*val = __le32_to_cpu(tmp);			\
		ret;							\
	 })
Loading