All of lore.kernel.org
 help / color / mirror / Atom feed
From: Arend van Spriel <arend@broadcom.com>
To: Ilya Faenson <ifaenson@broadcom.com>
Cc: Marcel Holtmann <marcel@holtmann.org>, <linux-bluetooth@vger.kernel.org>
Subject: Re: [RFC v3 4/4] BlueZ Broadcom UART Protocol
Date: Tue, 19 May 2015 14:47:46 +0200	[thread overview]
Message-ID: <555B30F2.7020605@broadcom.com> (raw)
In-Reply-To: <1431553823-25670-5-git-send-email-ifaenson@broadcom.com>

On 05/13/15 23:50, Ilya Faenson wrote:
> Enhance Broadcom protocol with the UART setup, firmware download
> and power management.
>
> Signed-off-by: Ilya Faenson<ifaenson@broadcom.com>
> ---
>   drivers/bluetooth/hci_bcm.c | 528 ++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 513 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c
> index 1ec0b4a..ccd92ed 100644
> --- a/drivers/bluetooth/hci_bcm.c
> +++ b/drivers/bluetooth/hci_bcm.c
> @@ -1,8 +1,9 @@
>   /*
>    *
> - *  Bluetooth HCI UART driver for Broadcom devices
> + *  Bluetooth UART H4 protocol for Broadcom devices
>    *
>    *  Copyright (C) 2015  Intel Corporation
> + *  Copyright (C) 2015  Broadcom Corporation
>    *
>    *
>    *  This program is free software; you can redistribute it and/or modify
> @@ -21,48 +22,413 @@
>    *
>    */
>
> +#include<linux/module.h>
>   #include<linux/kernel.h>
> +#include<linux/init.h>
> +#include<linux/types.h>
> +#include<linux/fcntl.h>
> +#include<linux/interrupt.h>
> +#include<linux/ptrace.h>
> +#include<linux/poll.h>
> +#include<linux/slab.h>
> +#include<linux/tty.h>
>   #include<linux/errno.h>
> +#include<linux/string.h>
> +#include<linux/signal.h>
> +#include<linux/ioctl.h>
>   #include<linux/skbuff.h>
> +#include<linux/gpio/consumer.h>
> +#include<linux/of_gpio.h>
> +#include<linux/of_platform.h>
>
>   #include<net/bluetooth/bluetooth.h>
>   #include<net/bluetooth/hci_core.h>
>
> -#include "btbcm.h"
>   #include "hci_uart.h"
> +#include "btbcm.h"
> +#include "btbcm_uart.h"
>
>   struct bcm_data {
>   	struct sk_buff *rx_skb;
>   	struct sk_buff_head txq;
> +	struct hci_uart *hu;
> +
> +	bool is_suspended; /* suspend/resume flag */
> +
> +	struct timer_list timer; /* idle timer */
> +
> +	struct btbcm_uart_parameters pars; /* device parameters */
> +	void *device_context; /* ACPI/DT device context */
>   };
>
> +/* Suspend/resume synchronization mutex */
> +static DEFINE_MUTEX(plock);
> +
> +/*
> + * Callbacks from the BCMBT_UART device
> + */
> +
> +/*
> + * The platform is suspending. Stop UART activity
> + */
> +static void suspend_notification(void *context)
> +{
> +	struct ktermios ktermios;
> +	struct hci_uart *hu = (struct hci_uart *)context;
> +	struct bcm_data *h4 = hu->priv;
> +	struct tty_struct *tty = hu->tty;
> +	int status;
> +	unsigned int set = 0;
> +	unsigned int clear = 0;
> +
> +	BT_DBG("suspend_notification with is_suspended %d", h4->is_suspended);
> +
> +	if (!h4->pars.configure_sleep)
> +		return;
> +
> +	if (!h4->is_suspended) {
> +		if (h4->pars.manual_fc) {
> +			/* Disable hardware flow control */
> +			ktermios = tty->termios;
> +			ktermios.c_cflag&= ~CRTSCTS;
> +			status = tty_set_termios(tty,&ktermios);
> +			if (status)
> +				BT_DBG("suspend_notification dis fc fail %d",
> +				       status);
> +			else
> +				BT_DBG("suspend_notification hw fc disabled");
> +
> +			/* Clear RTS to prevent the device from sending */
> +			/* (most PCs need OUT2 to enable interrupts)    */
> +			status = tty->driver->ops->tiocmget(tty);
> +			BT_DBG("suspend_notification cur tiocm 0x%x", status);
> +			set&= ~(TIOCM_OUT2 | TIOCM_RTS);
> +			clear = ~set;
> +			set&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			clear&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			status = tty->driver->ops->tiocmset(tty, set, clear);
> +			if (status)
> +				BT_DBG("suspend_notification clr RTS fail %d",
> +				       status);
> +			else
> +				BT_DBG("suspend_notification RTS cleared");
> +			status = tty->driver->ops->tiocmget(tty);
> +			BT_DBG("suspend_notification end tiocm 0x%x", status);
> +		}
> +
> +		/* Once this callback returns, driver suspends BT via GPIO */
> +		h4->is_suspended = true;
> +	}
> +}
> +
> +/*
> + * The platform is resuming. Resume UART activity.
> + */
> +static void resume_notification(void *context)
> +{
> +	struct ktermios ktermios;
> +	struct hci_uart *hu = (struct hci_uart *)context;
> +	struct bcm_data *h4 = hu->priv;
> +	struct tty_struct *tty = hu->tty;
> +	int status;
> +	unsigned int set = 0;
> +	unsigned int clear = 0;
> +
> +	BT_DBG("resume_notification with is_suspended %d", h4->is_suspended);
> +
> +	if (!h4->pars.configure_sleep)
> +		return;
> +
> +	/* When this callback executes, the device has woken up already */
> +	if (h4->is_suspended) {
> +		h4->is_suspended = false;
> +
> +		if (h4->pars.manual_fc) {
> +			status = tty->driver->ops->tiocmget(tty);
> +			BT_DBG("resume_notification cur tiocm 0x%x", status);
> +			set |= (TIOCM_OUT2 | TIOCM_RTS);
> +			clear = ~set;
> +			set&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			clear&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			status = tty->driver->ops->tiocmset(tty, set, clear);
> +			if (status)
> +				BT_DBG("resume_notification set RTS fail %d",
> +				       status);
> +			else
> +				BT_DBG("resume_notification RTS set");
> +
> +			/* Re-enable hardware flow control */
> +			ktermios = tty->termios;
> +			ktermios.c_cflag |= CRTSCTS;
> +			status = tty_set_termios(tty,&ktermios);
> +			if (status)
> +				BT_DBG("resume_notification enable fc fail %d",
> +				       status);
> +			else
> +				BT_DBG("resume_notification hw fc re-enabled");
> +		}
> +	}
> +
> +	/* If we're resumed, the idle timer must be running */
> +	status = mod_timer(&h4->timer, jiffies +
> +	    msecs_to_jiffies(h4->pars.idle_timeout_in_secs * 1000));
> +}
> +
> +/*
> + * The BT device is resuming. Resume UART activity if suspended
> + */
> +static void wakeup_notification(void *context)
> +{
> +	struct ktermios ktermios;
> +	struct hci_uart *hu = (struct hci_uart *)context;
> +	struct bcm_data *h4 = hu->priv;
> +	struct tty_struct *tty = hu->tty;
> +	int status;
> +	unsigned int set = 0;
> +	unsigned int clear = 0;
> +
> +	if (!h4->pars.configure_sleep)
> +		return;
> +
> +	status = tty->driver->ops->tiocmget(tty);
> +	BT_DBG("wakeup_notification hu %p current tiocm 0x%x", hu, status);
> +	if (h4->is_suspended) {
> +		if (h4->pars.manual_fc) {
> +			set |= (TIOCM_OUT2 | TIOCM_RTS);
> +			clear = ~set;
> +			set&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			clear&= TIOCM_DTR | TIOCM_RTS | TIOCM_OUT1 |
> +				TIOCM_OUT2 | TIOCM_LOOP;
> +			status = tty->driver->ops->tiocmset(tty, set, clear);
> +			if (status)
> +				BT_DBG("wakeup_notification set RTS fail %d",
> +				       status);
> +			else
> +				BT_DBG("wakeup_notification RTS set");
> +
> +			/* Re-enable hardware flow control */
> +			ktermios = tty->termios;
> +			ktermios.c_cflag |= CRTSCTS;
> +			status = tty_set_termios(tty,&ktermios);
> +			if (status)
> +				BT_DBG("wakeup_notification fc-en failure %d",
> +				       status);
> +			else
> +				BT_DBG("wakeup_notification hw fc re-enabled");
> +		}
> +
> +		h4->is_suspended = false;
> +	}
> +
> +	/* If we're resumed, the idle timer must be running */
> +	status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies(
> +			   h4->pars.idle_timeout_in_secs * 1000));
> +}
> +
> +/*
> + * Make sure we're awake
> + * (called when the resumed state is required)
> + */
> +static void bcm_ensure_wakeup(struct hci_uart *hu)
> +{
> +	struct bcm_data *h4 = hu->priv;
> +	int status;
> +
> +	if (!h4->pars.configure_sleep)
> +		return;
> +
> +	/* Suspend/resume operations are serialized */
> +	mutex_lock(&plock);
> +
> +	/* Nothing to do if resumed already */
> +	if (!h4->is_suspended) {
> +		mutex_unlock(&plock);
> +
> +		/* Just reset the timer */
> +		status = mod_timer(&h4->timer, jiffies + msecs_to_jiffies(
> +				   h4->pars.idle_timeout_in_secs * 1000));
> +		return;
> +	}
> +
> +	/* Wakeup the device */
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_RESUME,
> +				    h4->device_context, NULL, NULL);
> +	if (status)
> +		BT_DBG("bcm_ensure_wakeup failed to resume driver %d", status);
> +
> +	/* Unflow control the port if configured */
> +	resume_notification(hu);
> +
> +	mutex_unlock(&plock);
> +}
> +
> +/*
> + * Idle timer callback
> + */
> +static void bcm_idle_timeout(unsigned long arg)
> +{
> +	struct hci_uart *hu = (struct hci_uart *)arg;
> +	struct bcm_data *h4 = hu->priv;
> +	int status;
> +
> +	BT_DBG("bcm_idle_timeout hu %p", hu);
> +
> +	/* Suspend/resume operations are serialized */
> +	mutex_lock(&plock);
> +
> +	if (!h4->is_suspended) {
> +		/* Flow control the port if configured */
> +		suspend_notification(hu);
> +
> +		/* Suspend the device */
> +		status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND,
> +					    h4->device_context, NULL, NULL);
> +		if (status)
> +			BT_DBG("bcm_idle_timeout failed to suspend device %d",
> +			       status);
> +	}
> +
> +	mutex_unlock(&plock);
> +}
> +
>   static int bcm_open(struct hci_uart *hu)
>   {
> -	struct bcm_data *bcm;
> +	struct btbcm_uart_callbacks callbacks;
> +	unsigned long callbacks_size = sizeof(callbacks);
> +	int status;
> +	struct bcm_data *h4;
> +	struct tty_struct *tty = hu->tty;
>
> -	BT_DBG("hu %p", hu);
> +	BT_DBG("bcm_h4_open hu %p", hu);
>
> -	bcm = kzalloc(sizeof(*bcm), GFP_KERNEL);
> -	if (!bcm)
> +	h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
> +	if (!h4)
>   		return -ENOMEM;
>
> -	skb_queue_head_init(&bcm->txq);
> +	skb_queue_head_init(&h4->txq);
> +	hu->priv = h4;
> +	h4->hu = hu;
> +	h4->is_suspended = false;
> +
> +	/* Configure callbacks on the driver */
> +	callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION;
> +	callbacks.context = hu;
> +	strcpy(callbacks.name, tty->name);
> +	callbacks.p_suspend = suspend_notification;
> +	callbacks.p_resume = resume_notification;
> +	callbacks.p_wakeup = wakeup_notification;
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS,
> +				    NULL,&callbacks,&callbacks_size);
> +	if (status) {
> +		BT_DBG("bcm_h4_open failed to set driver callbacks %d", status);
> +		return status;
> +	}
> +	if (callbacks_size != sizeof(void *)) {
> +		BT_DBG("bcm_h4_open got back %d bytes from callbacks?!",
> +		       (int)callbacks_size);
> +		return -EMSGSIZE;
> +	}
> +	memcpy(&h4->device_context,&callbacks, sizeof(void *));
> +	BT_DBG("bcm_h4_open callbacks context %p", h4->device_context);
> +
> +	/* Retrieve device parameters */
> +	callbacks_size = sizeof(h4->pars);
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_GET_PARAMETERS,
> +				    h4->device_context,&h4->pars,
> +				&callbacks_size);
> +	if (status) {
> +		BT_DBG("bcm_h4_open failed to get dev parameters %d", status);
> +		return status;
> +	}
> +	BT_DBG("Pars ver %d csleep %d dalow %d balow %d idle %d",
> +	       h4->pars.interface_version, h4->pars.configure_sleep,
> +	       h4->pars.dev_wake_active_low, h4->pars.bt_wake_active_low,
> +	       h4->pars.idle_timeout_in_secs);
> +
> +	/* Cycle power to make sure the device is in the known state */
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF,
> +				    h4->device_context, NULL, NULL);
> +	if (status) {
> +		BT_DBG("bcm_h4_open failed to power off %d", status);
> +	} else {
> +		status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_ON,
> +					    h4->device_context, NULL, NULL);
> +		if (status)
> +			BT_DBG("bcm_h4_open failed to power on %d", status);
> +	}
> +
> +	/* Start the idle timer */
> +	if (h4->pars.configure_sleep) {
> +		setup_timer(&h4->timer, bcm_idle_timeout, (unsigned long)hu);
> +		if (h4->pars.configure_sleep)
> +			mod_timer(&h4->timer, jiffies + msecs_to_jiffies(
> +				  h4->pars.idle_timeout_in_secs * 1000));
> +	}
>
> -	hu->priv = bcm;
>   	return 0;
>   }
>
>   static int bcm_close(struct hci_uart *hu)
>   {
> -	struct bcm_data *bcm = hu->priv;
> +	struct btbcm_uart_callbacks callbacks;
> +	unsigned long callbacks_size = sizeof(callbacks);
> +	struct bcm_data *h4 = hu->priv;
> +	int status;
>
> -	BT_DBG("hu %p", hu);
> +	hu->priv = NULL;
>
> -	skb_queue_purge(&bcm->txq);
> -	kfree_skb(bcm->rx_skb);
> -	kfree(bcm);
> +	BT_DBG("bcm_h4_close hu %p", hu);
> +
> +	/* If we're being closed, we must suspend */
> +	if (h4->pars.configure_sleep) {
> +		mutex_lock(&plock);
> +
> +		if (!h4->is_suspended) {
> +			/* Flow control the port */
> +			suspend_notification(hu);
> +
> +			/* Suspend the device */
> +			status = btbcm_uart_control(BTBCM_UART_ACTION_SUSPEND,
> +						    h4->device_context, NULL,
> +						    NULL);
> +			if (status) {
> +				BT_DBG("bcm_h4_close suspend driver fail %d",
> +				       status);
> +			}
> +		}
> +
> +	mutex_unlock(&plock);
> +
> +	del_timer_sync(&h4->timer);
> +	}
> +
> +	/* Power off the device if possible */
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_POWER_OFF,
> +				    h4->device_context, NULL, NULL);
> +	if (status)
> +		BT_DBG("bcm_h4_close failed to power off %d", status);
> +
> +	/* de-configure callbacks on the driver */
> +	callbacks.interface_version = BTBCM_UART_INTERFACE_VERSION;
> +	callbacks.context = hu;
> +	callbacks.p_suspend = NULL;
> +	callbacks.p_resume = NULL;
> +	callbacks.p_wakeup = NULL;
> +	status = btbcm_uart_control(BTBCM_UART_ACTION_CONFIGURE_CALLBACKS,
> +				    h4->device_context,&callbacks,
> +				&callbacks_size);
> +	if (status)
> +		BT_DBG("bcm_h4_close failed to reset drv callbacks %d", status);
> +	skb_queue_purge(&h4->txq);
>
>   	hu->priv = NULL;
> +	kfree(h4);
> +
>   	return 0;
>   }
>
> @@ -79,11 +445,137 @@ static int bcm_flush(struct hci_uart *hu)
>
>   static int bcm_setup(struct hci_uart *hu)
>   {
> -	BT_DBG("hu %p", hu);
> +	struct bcm_data *h4 = hu->priv;
> +	int status;
> +	struct sk_buff *skb;
> +	unsigned char sleep_pars[] = {
> +	0x01,       /* sleep mode 1=UART */
> +	0x02,       /* idle threshold HOST (value * 300ms) */
> +	0x02,       /* idle threshold HC   (value * 300ms) */
> +	0x01,       /* BT_WAKE active mode - 1=active high, 0 = active low */
> +	0x00,       /* HOST_WAKE active mode - 1=active high, 0 = active low */
> +	0x01,       /* Allow host sleep during SCO - FALSE */
> +	0x01,       /* combine sleep mode and LPM - 1 == TRUE */
> +	0x00,       /* enable tristate control of UART TX line - FALSE */
> +	0x00,       /* USB auto-sleep on USB SUSPEND */
> +	0x00,       /* USB USB RESUME timeout (seconds) */
> +	0x00,       /* Pulsed Host Wake */
> +	0x00        /* Enable Break To Host */
> +	};
> +	unsigned char pcm_int_pars[] = {
> +	0x00,       /* 0=PCM routing, 1=SCO over HCI */
> +	0x02,       /* 0=128Kbps,1=256Kbps,2=512Kbps,3=1024Kbps,4=2048Kbps */
> +	0x00,       /* short frame sync  0=short, 1=long */
> +	0x00,       /* sync mode         0=slave, 1=master */
> +	0x00        /* clock mode        0=slave, 1=master */
> +	};
> +	unsigned char pcm_format_pars[] = {
> +	0x00,       /* LSB_First 1=TRUE, 0=FALSE */
> +	0x00,       /* Fill_Value (use 0-7 for fill bits value) */
> +	0x02,       /* Fill_Method   (2=sign extended) */
> +	0x03,       /* Fill_Num      # of fill bits 0-3) */
> +	0x01        /* Right_Justify 1=TRUE, 0=FALSE */
> +	};
> +	unsigned char time_slot_number = 0;
> +
> +	BT_DBG("bcm_h4_setup hu %p", hu);
> +
> +	/* Bring the UART into known default state */
> +	status = btbcm_init_uart(hu);
> +	if (status) {
> +		BT_DBG("bcm_h4_setup failed to init BT device %d", status);
> +		return status;
> +	}
> +
> +	/* Basic sanity check */
> +	skb = __hci_cmd_sync(hu->hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
> +	if (IS_ERR(skb)) {
> +		status = PTR_ERR(skb);
> +		BT_ERR("bcm_h4_setup HCI Reset failed (%d)", status);
> +		return status;
> +	}
> +	kfree_skb(skb);
> +	BT_DBG("bcm_h4_setup HCI Reset succeeded");
> +
> +	/* Set the new baud rate */
> +	status = btbcm_set_baud_rate(hu,
> +				     h4->pars.baud_rate_before_config_download);
> +	if (status) {
> +		BT_ERR("bcm_h4_setup set_baud_rate faiilure %d", status);
> +		return status;
> +	}
>
>   	hu->hdev->set_bdaddr = btbcm_set_bdaddr;
>
> -	return btbcm_setup_patchram(hu->hdev);
> +	/* Download the firmware and reconfigure the UART afterwards */
> +	status = btbcm_setup_patchram(hu->hdev);
> +	if (status) {
> +		BT_ERR("bcm_h4_setup setup_patchram faiilure %d", status);
> +		return status;
> +	}
> +
> +	/* Configure SCO PCM parameters */
> +	if (h4->pars.configure_audio) {
> +		pcm_int_pars[0] = h4->pars.PCMRouting;
> +		pcm_int_pars[1] = h4->pars.PCMInCallBitclock;
> +		pcm_int_pars[2] = h4->pars.PCMShortFrameSync;
> +		pcm_int_pars[3] = h4->pars.PCMSyncMode;
> +		pcm_int_pars[4] = h4->pars.PCMClockMode;
> +		skb = __hci_cmd_sync(hu->hdev, 0xfc1c, sizeof(pcm_int_pars),

Guess 0xfc1c is the hci command. Can you create a define for them?

Regards,
Arend

> +				     pcm_int_pars, HCI_INIT_TIMEOUT);
> +		if (IS_ERR(skb)) {
> +			status = PTR_ERR(skb);
> +			BT_ERR("bcm_h4_setup PCM INT VSC failed (%d)", status);
> +			return status;
> +		}
> +		kfree_skb(skb);
> +		BT_DBG("bcm_h4_setup PCM INT Parameters VSC succeeded");
> +
> +		pcm_format_pars[0] = h4->pars.PCMLSBFirst;
> +		pcm_format_pars[1] = h4->pars.PCMFillValue;
> +		pcm_format_pars[2] = h4->pars.PCMFillMethod;
> +		pcm_format_pars[3] = h4->pars.PCMFillNum;
> +		pcm_format_pars[4] = h4->pars.PCMRightJustify;
> +		skb = __hci_cmd_sync(hu->hdev, 0xfc1e, sizeof(pcm_format_pars),
> +				     pcm_format_pars, HCI_INIT_TIMEOUT);
> +		if (IS_ERR(skb)) {
> +			status = PTR_ERR(skb);
> +			BT_ERR("bcm_h4_setup PCM Format VSC failed (%d)",
> +			       status);
> +			return status;
> +		}
> +		kfree_skb(skb);
> +		BT_DBG("bcm_h4_setup PCM Format VSC succeeded");
> +
> +		skb = __hci_cmd_sync(hu->hdev, 0xfc22, sizeof(time_slot_number),
> +				&time_slot_number, HCI_INIT_TIMEOUT);
> +		if (IS_ERR(skb)) {
> +			status = PTR_ERR(skb);
> +			BT_ERR("bcm_h4_setup SCO Time Slot VSC failed (%d)",
> +			       status);
> +			return status;
> +		}
> +		kfree_skb(skb);
> +		BT_DBG("bcm_h4_setup SCO Time Slot VSC succeeded");
> +	}
> +
> +	/* Configure device's suspend/resume operation */
> +	if (h4->pars.configure_sleep) {
> +		/* Override the default */
> +		sleep_pars[3] = (unsigned char)!h4->pars.bt_wake_active_low;
> +		sleep_pars[4] = (unsigned char)!h4->pars.dev_wake_active_low;
> +		skb = __hci_cmd_sync(hu->hdev, 0xfc27, sizeof(sleep_pars),
> +				     sleep_pars, HCI_INIT_TIMEOUT);
> +		if (IS_ERR(skb)) {
> +			status = PTR_ERR(skb);
> +			BT_ERR("bcm_h4_setup Sleep VSC failed (%d)", status);
> +			return status;
> +		}
> +		kfree_skb(skb);
> +		BT_DBG("bcm_h4_setup Set Sleep Parameters VSC succeeded");
> +	}
> +
> +	return 0;
>   }
>
>   static const struct h4_recv_pkt bcm_recv_pkts[] = {
> @@ -99,6 +591,9 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count)
>   	if (!test_bit(HCI_UART_REGISTERED,&hu->flags))
>   		return -EUNATCH;
>
> +	/* Make sure we're resumed */
> +	bcm_ensure_wakeup(hu);
> +
>   	bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count,
>   				  bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts));
>   	if (IS_ERR(bcm->rx_skb)) {
> @@ -116,6 +611,9 @@ static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb)
>
>   	BT_DBG("hu %p skb %p", hu, skb);
>
> +	/* Make sure we're resumed */
> +	bcm_ensure_wakeup(hu);
> +
>   	/* Prepend skb with frame type */
>   	memcpy(skb_push(skb, 1),&bt_cb(skb)->pkt_type, 1);
>   	skb_queue_tail(&bcm->txq, skb);

  reply	other threads:[~2015-05-19 12:47 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-13 21:50 [RFC v3 0/4] Broadcom Bluetooth UART device driver Ilya Faenson
2015-05-13 21:50 ` [RFC v3 1/4] Broadcom Bluetooth UART Device Tree bindings Ilya Faenson
2015-05-19  9:22   ` Arend van Spriel
2015-05-22 19:05     ` Ilya Faenson
2015-05-13 21:50 ` [RFC v3 2/4] Broadcom Bluetooth UART Platform Driver Ilya Faenson
2015-05-19 12:42   ` Arend van Spriel
2015-05-22 19:05     ` Ilya Faenson
2015-05-13 21:50 ` [RFC v3 3/4] Broadcom Bluetooth protocol UART support Ilya Faenson
2015-05-13 21:50 ` [RFC v3 4/4] BlueZ Broadcom UART Protocol Ilya Faenson
2015-05-19 12:47   ` Arend van Spriel [this message]
2015-05-19 15:20     ` Marcel Holtmann
2015-05-20  7:19       ` Arend van Spriel
2015-05-19  8:19 ` [RFC v3 0/4] Broadcom Bluetooth UART device driver Arend van Spriel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=555B30F2.7020605@broadcom.com \
    --to=arend@broadcom.com \
    --cc=ifaenson@broadcom.com \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=marcel@holtmann.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.