diff options
Diffstat (limited to 'drivers/bluetooth/btmrvl_sdio.c')
| -rw-r--r-- | drivers/bluetooth/btmrvl_sdio.c | 111 | 
1 files changed, 55 insertions, 56 deletions
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index df0773ebd9e..dcc2a6ec23f 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -47,6 +47,7 @@   * module_exit function is called.   */  static u8 user_rmmod; +static u8 sdio_ireg;  static const struct btmrvl_sdio_device btmrvl_sdio_sd6888 = {  	.helper		= "sd8688_helper.bin", @@ -83,10 +84,10 @@ static int btmrvl_sdio_read_fw_status(struct btmrvl_sdio_card *card, u16 *dat)  	*dat = 0;  	fws0 = sdio_readb(card->func, CARD_FW_STATUS0_REG, &ret); +	if (ret) +		return -EIO; -	if (!ret) -		fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret); - +	fws1 = sdio_readb(card->func, CARD_FW_STATUS1_REG, &ret);  	if (ret)  		return -EIO; @@ -216,7 +217,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)  	tmphlprbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); -	tmphlprbuf = kmalloc(tmphlprbufsz, GFP_KERNEL); +	tmphlprbuf = kzalloc(tmphlprbufsz, GFP_KERNEL);  	if (!tmphlprbuf) {  		BT_ERR("Unable to allocate buffer for helper."  			" Terminating download"); @@ -224,8 +225,6 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)  		goto done;  	} -	memset(tmphlprbuf, 0, tmphlprbufsz); -  	helperbuf = (u8 *) ALIGN_ADDR(tmphlprbuf, BTSDIO_DMA_ALIGN);  	/* Perform helper data transfer */ @@ -318,7 +317,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)  	BT_DBG("Downloading FW image (%d bytes)", firmwarelen);  	tmpfwbufsz = ALIGN_SZ(BTM_UPLD_SIZE, BTSDIO_DMA_ALIGN); -	tmpfwbuf = kmalloc(tmpfwbufsz, GFP_KERNEL); +	tmpfwbuf = kzalloc(tmpfwbufsz, GFP_KERNEL);  	if (!tmpfwbuf) {  		BT_ERR("Unable to allocate buffer for firmware."  		       " Terminating download"); @@ -326,8 +325,6 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)  		goto done;  	} -	memset(tmpfwbuf, 0, tmpfwbufsz); -  	/* Ensure aligned firmware buffer */  	fwbuf = (u8 *) ALIGN_ADDR(tmpfwbuf, BTSDIO_DMA_ALIGN); @@ -555,78 +552,79 @@ exit:  	return ret;  } -static int btmrvl_sdio_get_int_status(struct btmrvl_private *priv, u8 * ireg) +static int btmrvl_sdio_process_int_status(struct btmrvl_private *priv)  { -	int ret; -	u8 sdio_ireg = 0; +	ulong flags; +	u8 ireg;  	struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; -	*ireg = 0; - -	sdio_ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); -	if (ret) { -		BT_ERR("sdio_readb: read int status register failed"); -		ret = -EIO; -		goto done; -	} - -	if (sdio_ireg != 0) { -		/* -		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS -		 * Clear the interrupt status register and re-enable the -		 * interrupt. -		 */ -		BT_DBG("sdio_ireg = 0x%x", sdio_ireg); - -		sdio_writeb(card->func, ~(sdio_ireg) & (DN_LD_HOST_INT_STATUS | -							UP_LD_HOST_INT_STATUS), -			    HOST_INTSTATUS_REG, &ret); -		if (ret) { -			BT_ERR("sdio_writeb: clear int status register " -				"failed"); -			ret = -EIO; -			goto done; -		} -	} +	spin_lock_irqsave(&priv->driver_lock, flags); +	ireg = sdio_ireg; +	sdio_ireg = 0; +	spin_unlock_irqrestore(&priv->driver_lock, flags); -	if (sdio_ireg & DN_LD_HOST_INT_STATUS) { +	sdio_claim_host(card->func); +	if (ireg & DN_LD_HOST_INT_STATUS) {  		if (priv->btmrvl_dev.tx_dnld_rdy)  			BT_DBG("tx_done already received: " -				" int_status=0x%x", sdio_ireg); +				" int_status=0x%x", ireg);  		else  			priv->btmrvl_dev.tx_dnld_rdy = true;  	} -	if (sdio_ireg & UP_LD_HOST_INT_STATUS) +	if (ireg & UP_LD_HOST_INT_STATUS)  		btmrvl_sdio_card_to_host(priv); -	*ireg = sdio_ireg; - -	ret = 0; +	sdio_release_host(card->func); -done: -	return ret; +	return 0;  }  static void btmrvl_sdio_interrupt(struct sdio_func *func)  {  	struct btmrvl_private *priv; -	struct hci_dev *hcidev;  	struct btmrvl_sdio_card *card; +	ulong flags;  	u8 ireg = 0; +	int ret;  	card = sdio_get_drvdata(func); -	if (card && card->priv) { -		priv = card->priv; -		hcidev = priv->btmrvl_dev.hcidev; +	if (!card || !card->priv) { +		BT_ERR("sbi_interrupt(%p) card or priv is " +				"NULL, card=%p\n", func, card); +		return; +	} -		if (btmrvl_sdio_get_int_status(priv, &ireg)) -			BT_ERR("reading HOST_INT_STATUS_REG failed"); -		else -			BT_DBG("HOST_INT_STATUS_REG %#x", ireg); +	priv = card->priv; + +	ireg = sdio_readb(card->func, HOST_INTSTATUS_REG, &ret); +	if (ret) { +		BT_ERR("sdio_readb: read int status register failed"); +		return; +	} + +	if (ireg != 0) { +		/* +		 * DN_LD_HOST_INT_STATUS and/or UP_LD_HOST_INT_STATUS +		 * Clear the interrupt status register and re-enable the +		 * interrupt. +		 */ +		BT_DBG("ireg = 0x%x", ireg); -		btmrvl_interrupt(priv); +		sdio_writeb(card->func, ~(ireg) & (DN_LD_HOST_INT_STATUS | +					UP_LD_HOST_INT_STATUS), +				HOST_INTSTATUS_REG, &ret); +		if (ret) { +			BT_ERR("sdio_writeb: clear int status register failed"); +			return; +		}  	} + +	spin_lock_irqsave(&priv->driver_lock, flags); +	sdio_ireg |= ireg; +	spin_unlock_irqrestore(&priv->driver_lock, flags); + +	btmrvl_interrupt(priv);  }  static int btmrvl_sdio_register_dev(struct btmrvl_sdio_card *card) @@ -930,6 +928,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,  	/* Initialize the interface specific function pointers */  	priv->hw_host_to_card = btmrvl_sdio_host_to_card;  	priv->hw_wakeup_firmware = btmrvl_sdio_wakeup_fw; +	priv->hw_process_int_status = btmrvl_sdio_process_int_status;  	if (btmrvl_register_hdev(priv)) {  		BT_ERR("Register hdev failed!");  |