* Compilation using clang
From: Donald Carr @ 2014-01-10 17:57 UTC (permalink / raw)
To: linux-bluetooth
Top of the morning,
qtconnectivity currently contains a kludge which is required due to
the use of the GCC typeof extension in bluetooth.h which is breaking
with Clang compilation against the cxx11 spec.
The kludge in question involves molesting the standard (eg -std=cxx11)
specified to the compiler (explicitly away from cxx11 toward g++0x)
and hence I am hoping to be able to murder its intrusive self. I am
not entirely clear on the nuances though:
This is the offending section:
#define bt_get_unaligned(ptr) \
({ \
struct __attribute__((packed)) { \
typeof(*(ptr)) __v; \
} *__p = (typeof(__p)) (ptr); \
__p->__v; \
})
#define bt_put_unaligned(val, ptr) \
do { \
struct __attribute__((packed)) { \
typeof(*(ptr)) __v; \
} *__p = (typeof(__p)) (ptr); \
__p->__v = (val); \
} while(0)
and changing typeof to __typeof__ has been verified to succeed in the
stated circumstance. I don't know whether this is the ideal solution,
or whether decltype or so other designator would be a closer/better
match.
Any feedback would be greatly appreciated, I am using this change
locally and I think it could be of broader use to people.
Yours sincerely,
Donald Carr
--
-------------------------------
°v° Donald Carr
/(_)\ Vaguely Professional Penguin lover
^ ^
Cave canem, te necet lingendo
^ permalink raw reply
* Re: [PATCH v5] Bluetooth: Add hci_h4p driver
From: Joe Perches @ 2014-01-10 17:33 UTC (permalink / raw)
To: Pavel Machek
Cc: Marcel Holtmann, Pali Rohár,
Ивайло Димитров,
Gustavo F. Padovan, Johan Hedberg, linux-kernel,
linux-bluetooth@vger.kernel.org development, Ville Tervo,
Sebastian Reichel
In-Reply-To: <20140110145207.GB12048@amd.pavel.ucw.cz>
On Fri, 2014-01-10 at 15:52 +0100, Pavel Machek wrote:
> Add hci_h4p bluetooth driver to bluetooth-next. This device is used
> for example on Nokia N900 cell phone.
some mostly trivial comments:
> diff --git a/drivers/bluetooth/nokia_core.c b/drivers/bluetooth/nokia_core.c
[]
> +static void hci_h4p_disable_tx(struct hci_h4p_info *info)
> +{
> + BT_DBG("\n");
function tracers aren't generally useful.
> +void hci_h4p_enable_tx(struct hci_h4p_info *info)
> +{
> + unsigned long flags;
> + BT_DBG("\n");
etc...
> +static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
> +{
> + BT_DBG("Negotiation succesful\n");
3 s's in successful
[]
> +static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
pretty big function to be inline
> +{
> + switch (info->rx_state) {
[]
> + case WAIT_FOR_HEADER:
> + info->rx_count--;
> + *skb_put(info->rx_skb, 1) = byte;
> + if (info->rx_count == 0) {
> + info->rx_count = hci_h4p_get_data_len(info,
> + info->rx_skb);
> + if (info->rx_count > skb_tailroom(info->rx_skb)) {
> + dev_err(info->dev, "Too long frame.\n");
> + info->garbage_bytes = info->rx_count -
> + skb_tailroom(info->rx_skb);
> + kfree_skb(info->rx_skb);
> + info->rx_skb = NULL;
> + break;
> + }
> + info->rx_state = WAIT_FOR_DATA;
> +
> + }
> + break;
Perhaps better to write with fewer indentations:
case WAIT_FOR_HEADER:
info->rx_count--;
*skb_put(info->rx_skb, 1) = byte;
if (info->rx_count != 0)
break;
info->rx_count = hci_h4p_get_data_len(info, info->rx_skb);
if (info->rx_count > skb_tailroom(info->rx_skb)) {
dev_err(info->dev, "frame too long\n");
info->garbage_bytes = info->rx_count
- skb_tailroom(info->rx_skb);
kfree_skb(info->rx_skb);
info->rx_skb = NULL;
break;
}
info->rx_state = WAIT_FOR_DATA;
break;
[]
> + if (info->rx_count == 0) {
> + /* H4+ devices should allways send word aligned
> + * packets */
s/allways/always/
80 columns are available and this could be a single line comment
/* H4+ devices should always send word aligned packets */
[]
> +static void hci_h4p_rx_tasklet(unsigned long data)
> +{
[]
> + while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
[]
> + pr_debug("0x%.2x ", byte);
pr_debug is prefixed by a newline if necessary
and then <7>, one for each use.
This will produce a lot of dmesg output lines
(1 for each byte) and isn't in my opinion
necessary/useful.
> + hci_h4p_handle_byte(info, byte);
> + }
> +
> + if (!info->rx_enabled) {
> + if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
> + info->autorts) {
> + __hci_h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS);
> + info->autorts = 0;
> + }
> + /* Flush posted write to avoid spurious interrupts */
> + hci_h4p_inb(info, UART_OMAP_SCR);
> + hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
> + }
> +
> +finish_rx:
> + pr_debug("\n");
here too.
> +static void hci_h4p_tx_tasklet(unsigned long data)
> +{
[]
> + if (!skb) {
> + /* No data in buffer */
> + BT_DBG("skb ready\n");
> + if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
> + hci_h4p_outb(info, UART_IER,
> + hci_h4p_inb(info, UART_IER) &
> + ~UART_IER_THRI);
> + hci_h4p_inb(info, UART_OMAP_SCR);
> + hci_h4p_disable_tx(info);
> + return;
> + } else
unnecessary else
> + hci_h4p_outb(info, UART_OMAP_SCR,
> + hci_h4p_inb(info, UART_OMAP_SCR) |
> + UART_OMAP_SCR_EMPTY_THR);
and unnecessary indentation
> + goto finish_tx;
> + }
> +
> + /* Copy data to tx fifo */
> + while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
> + (sent < skb->len)) {
> + pr_debug("0x%.2x ", skb->data[sent]);
More unnecessary pr_debug
> +static inline void hci_h4p_set_pm_limits(struct hci_h4p_info *info, bool set)
> +{
> + struct hci_h4p_platform_data *bt_plat_data = info->dev->platform_data;
> + char *sset = set ? "set" : "clear";
const?
> +
> + if (unlikely(!bt_plat_data || !bt_plat_data->set_pm_limits))
> + return;
> +
> + if (set != !!test_bit(H4P_ACTIVE_MODE, &info->pm_flags)) {
> + bt_plat_data->set_pm_limits(info->dev, set);
> + if (set)
> + set_bit(H4P_ACTIVE_MODE, &info->pm_flags);
> + else
> + clear_bit(H4P_ACTIVE_MODE, &info->pm_flags);
> + BT_DBG("Change pm constraints to: %s", sset);
missing newline
> + return;
> + }
> +
> + BT_DBG("pm constraints remains: %s", sset);
here too
[]
> +static int hci_h4p_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> +{
> + struct hci_h4p_info *info;
> + int err = 0;
> +
> + if (!hdev) {
> + printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
> + return -ENODEV;
> + }
Is this possible?
> +static ssize_t hci_h4p_store_bdaddr(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct hci_h4p_info *info = dev_get_drvdata(dev);
> + unsigned int bdaddr[6];
> + int ret, i;
> +
> + ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
> + &bdaddr[0], &bdaddr[1], &bdaddr[2],
> + &bdaddr[3], &bdaddr[4], &bdaddr[5]);
> +
> + if (ret != 6)
> + return -EINVAL;
> +
> + for (i = 0; i < 6; i++)
> + info->bd_addr[i] = bdaddr[i] & 0xff;
This could also return -EINVAL if bdaddr[i] > 0xff
> +static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
> +{
> + int i;
> + static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
> + int not_valid;
> +
> + not_valid = 1;
> + for (i = 0; i < 6; i++) {
> + if (info->bd_addr[i] != 0x00) {
> + not_valid = 0;
> + break;
> + }
> + }
> +
> + if (not_valid) {
> + dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
> + /* When address is not valid, use some random but Nokia MAC */
> + memcpy(info->bd_addr, nokia_oui, 3);
> + get_random_bytes(info->bd_addr + 3, 3);
> + }
This seems wrong as addresses can have valid 0 bytes.
Perhaps use:
if (!is_valid_ether_addr(info->bd_addr))
[]
> +int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
> + struct sk_buff_head *fw_queue)
> +{
[]
> + /* Check if this is bd_address packet */
> + if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
> + offset = 21;
> + skb->data[offset + 1] = 0x00;
> + skb->data[offset + 5] = 0x00;
> +
> + not_valid = 1;
> + for (i = 0; i < 6; i++) {
> + if (info->bd_addr[i] != 0x00) {
> + not_valid = 0;
> + break;
> + }
> + }
> +
> + if (not_valid) {
> + dev_info(info->dev, "Valid bluetooth address not found,"
> + " setting some random\n");
!is_valid_ether_addr() here too
^ permalink raw reply
* [PATCH] tools/bluetooth-player: check path validity
From: Sebastian Chlad @ 2014-01-10 16:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
Bluetooth-player change-folder cmd approves any argument however it
can be and then should a valid path only. Failing in providing
a valid path crashes bluetooth-player thus argument should be
checked if it's a valid path.
---
tools/bluetooth-player.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tools/bluetooth-player.c b/tools/bluetooth-player.c
index 2afdd17..f10d9be 100644
--- a/tools/bluetooth-player.c
+++ b/tools/bluetooth-player.c
@@ -738,6 +738,11 @@ static void cmd_change_folder(int argc, char *argv[])
return;
}
+ if (dbus_validate_path(argv[1], NULL) == FALSE) {
+ rl_printf("Not a valid path\n");
+ return;
+ }
+
if (check_default_player() == FALSE)
return;
--
1.8.3.2
---------------------------------------------------------------------
Intel Finland Oy
Registered Address: PL 281, 00181 Helsinki
Business Identity Code: 0357606 - 4
Domiciled in Helsinki
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply related
* Re: [PATCH v2 0/7] Next skeleton patches for audio plugin
From: Luiz Augusto von Dentz @ 2014-01-10 15:49 UTC (permalink / raw)
To: Lukasz Rymanowski; +Cc: linux-bluetooth@vger.kernel.org, Johan Hedberg
In-Reply-To: <1389317068-12540-1-git-send-email-lukasz.rymanowski@tieto.com>
Hi Lukasz,
On Fri, Jan 10, 2014 at 3:24 AM, Lukasz Rymanowski
<lukasz.rymanowski@tieto.com> wrote:
> v1:
> Those patches adds function to handle send/receive msg on audio IPC.
> Also adds some small changes.
>
> Not that since we do not yet support AUDIO_OP_OPEN, audio socket will be
> reseted just after connect.
>
> v2:
> Fixes suggester by Luiz
> Some additional fixes
>
> Lukasz Rymanowski (7):
> android/audio: Prefix error log with "audio"
> android: Fix error check from pthread_create
> android/audio: Refactor create_audio_ipc
> android/audio: Trivial function move
> android/audio: Add skeleton for ipc_open_cmd function
> android/audio: Add audio_ipc_cmd
> android/audio: Add audio_ipc_cleanup function
>
> android/Makefile.am | 1 +
> android/hal-audio.c | 304 ++++++++++++++++++++++++++++++++++++++++++----------
> android/hal-ipc.c | 6 +-
> 3 files changed, 250 insertions(+), 61 deletions(-)
>
> --
> 1.8.4
Ive applied some of these set, any of those that involved the command
I left out for now since they are not complete and they would
otherwise just cause failures now that haltest does load
audio.a2dp.default.so.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH v3] android/tester: Multi property check for test case
From: Szymon Janc @ 2014-01-10 15:24 UTC (permalink / raw)
To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth
In-Reply-To: <1389363698-30492-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>
Hi Grzegorz,
On Friday 10 of January 2014 15:21:38 Grzegorz Kolodziejczyk wrote:
> This patch allows to check multiple properties for test case. Properties
> can be prioritized to allow check if they'll come in right order. Now
> properties aren't treated as a "single" callback. In future in one
> callback multiple properties can come.
> ---
> android/android-tester.c | 536 ++++++++++++++++++++++++++++++++++-------------
> 1 file changed, 392 insertions(+), 144 deletions(-)
Applied, thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* Re: [PATCH_v7 0/4] Add support for NAP role
From: Szymon Janc @ 2014-01-10 15:12 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1389363109-6312-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Hi Ravi,
On Friday 10 of January 2014 16:11:45 Ravi kumar Veeramally wrote:
> v7: Rebase issue with _v6.
>
> v6: Fixed Szymon's comments (use snprintf and defines).
>
> v5: Fixed Szymon's comments and added his fix (crash when bridge create
> fails).
>
> v4: Fixed Szymon's and Luiz's comments.
>
> v3: Fixed Johan's comments (removed fopen, fprintf and used open and write).
>
> v2: Fixed Johan's comments.
>
> v1: This patch set add support for NAP role. It register NAP server and create
> bnep bridge and listen for incoming connections from client devices.
> On incoming connection request it accepts connection, creates bnep interface
> and notifies control state and connection state infromation. Removes device
> on disconnect request. Android related changes are required to enable this
> role. Patches sent to respective ML.
>
> Ravi kumar Veeramally (4):
> android/pan: Register Network Access Point
> android/pan: Listen for incoming connections and accept in NAP role
> android/pan: Implement PAN enable HAL api at daemon side
> android/pan: Remove connected PAN devices on profile unregister call
>
> android/pan.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 327 insertions(+), 12 deletions(-)
>
All patches applied, thanks a lot.
--
Best regards,
Szymon Janc
^ permalink raw reply
* [PATCH] avrcp: Remove dead code
From: Andrei Emeltchenko @ 2014-01-10 14:56 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
session->target cannot be NULL since it is already checked 11 lines
above:
...
if (session == NULL || session->target == NULL)
return -ENOTCONN;
...
---
profiles/audio/avrcp.c | 24 ++++--------------------
1 file changed, 4 insertions(+), 20 deletions(-)
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
index 8d4309a..197959f 100644
--- a/profiles/audio/avrcp.c
+++ b/profiles/audio/avrcp.c
@@ -3722,30 +3722,14 @@ int avrcp_set_volume(struct btd_device *dev, uint8_t volume)
DBG("volume=%u", volume);
- if (session->target) {
- pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
- pdu->params[0] = volume;
- pdu->params_len = htons(1);
+ pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
+ pdu->params[0] = volume;
+ pdu->params_len = htons(1);
- return avctp_send_vendordep_req(session->conn,
+ return avctp_send_vendordep_req(session->conn,
AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL,
buf, sizeof(buf),
avrcp_handle_set_volume, session);
- } else if (session->registered_events &
- (1 << AVRCP_EVENT_VOLUME_CHANGED)) {
- uint8_t id = AVRCP_EVENT_VOLUME_CHANGED;
- pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
- pdu->params[0] = AVRCP_EVENT_VOLUME_CHANGED;
- pdu->params[1] = volume;
- pdu->params_len = htons(2);
-
- return avctp_send_vendordep(session->conn,
- session->transaction_events[id],
- AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
- buf, sizeof(buf));
- }
-
- return 0;
}
static int avrcp_connect(struct btd_service *service)
--
1.8.3.2
^ permalink raw reply related
* [PATCH v5] Bluetooth: Add hci_h4p driver
From: Pavel Machek @ 2014-01-10 14:52 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Pali Rohár,
Ивайло Димитров,
Gustavo F. Padovan, Johan Hedberg, linux-kernel,
linux-bluetooth@vger.kernel.org development, Ville Tervo,
Sebastian Reichel
In-Reply-To: <20140103001753.GA21023@amd.pavel.ucw.cz>
Add hci_h4p bluetooth driver to bluetooth-next. This device is used
for example on Nokia N900 cell phone.
Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
---
Changes from v4: Fixups, conversion to devm_* as suggested by
Sebastian. Please apply.
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 11a6104..a53e8c7 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -241,5 +241,15 @@ config BT_WILINK
core driver to communicate with the BT core of the combo chip.
Say Y here to compile support for Texas Instrument's WiLink7 driver
- into the kernel or say M to compile it as module.
+ into the kernel or say M to compile it as module (btwilink).
+
+config BT_NOKIA_H4P
+ tristate "HCI driver with H4 Nokia extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver with H4 extensions. This driver provides
+ support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+ Say Y here to compile support for h4 extended devices into the kernel
+ or say M to compile it as module (btnokia_h4p).
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 9fe8a87..6f25db2 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -31,4 +31,8 @@ hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
hci_uart-objs := $(hci_uart-y)
+obj-$(CONFIG_BT_NOKIA_H4P) += btnokia_h4p.o
+btnokia_h4p-objs := nokia_core.o nokia_fw.o nokia_uart.o nokia_fw-csr.o \
+ nokia_fw-bcm.o nokia_fw-ti1273.o
+
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/bluetooth/hci_h4p.h b/drivers/bluetooth/hci_h4p.h
new file mode 100644
index 0000000..fd7a640
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p.h
@@ -0,0 +1,228 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#define FW_NAME_TI1271_PRELE "ti1273_prele.bin"
+#define FW_NAME_TI1271_LE "ti1273_le.bin"
+#define FW_NAME_TI1271 "ti1273.bin"
+#define FW_NAME_BCM2048 "bcmfw.bin"
+#define FW_NAME_CSR "bc4fw.bin"
+
+#define UART_SYSC_OMAP_RESET 0x03
+#define UART_SYSS_RESETDONE 0x01
+#define UART_OMAP_SCR_EMPTY_THR 0x08
+#define UART_OMAP_SCR_WAKEUP 0x10
+#define UART_OMAP_SSR_WAKEUP 0x02
+#define UART_OMAP_SSR_TXFULL 0x01
+
+#define UART_OMAP_SYSC_IDLEMODE 0x03
+#define UART_OMAP_SYSC_IDLEMASK (3 << UART_OMAP_SYSC_IDLEMODE)
+
+#define UART_OMAP_SYSC_FORCE_IDLE (0 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_NO_IDLE (1 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_SMART_IDLE (2 << UART_OMAP_SYSC_IDLEMODE)
+
+#define H4P_TRANSFER_MODE 1
+#define H4P_SCHED_TRANSFER_MODE 2
+#define H4P_ACTIVE_MODE 3
+
+struct hci_h4p_info {
+ struct timer_list lazy_release;
+ struct hci_dev *hdev;
+ spinlock_t lock;
+
+ void __iomem *uart_base;
+ unsigned long uart_phys_base;
+ int irq;
+ struct device *dev;
+ u8 chip_type;
+ u8 bt_wakeup_gpio;
+ u8 host_wakeup_gpio;
+ u8 reset_gpio;
+ u8 reset_gpio_shared;
+ u8 bt_sysclk;
+ u8 man_id;
+ u8 ver_id;
+
+ struct sk_buff_head fw_queue;
+ struct sk_buff *alive_cmd_skb;
+ struct completion init_completion;
+ struct completion fw_completion;
+ struct completion test_completion;
+ int fw_error;
+ int init_error;
+
+ struct sk_buff_head txq;
+
+ struct sk_buff *rx_skb;
+ long rx_count;
+ unsigned long rx_state;
+ unsigned long garbage_bytes;
+
+ u8 bd_addr[6];
+ struct sk_buff_head *fw_q;
+
+ int pm_enabled;
+ int tx_enabled;
+ int autorts;
+ int rx_enabled;
+ unsigned long pm_flags;
+
+ int tx_clocks_en;
+ int rx_clocks_en;
+ spinlock_t clocks_lock;
+ struct clk *uart_iclk;
+ struct clk *uart_fclk;
+ atomic_t clk_users;
+ u16 dll;
+ u16 dlh;
+ u16 ier;
+ u16 mdr1;
+ u16 efr;
+};
+
+struct hci_h4p_radio_hdr {
+ __u8 evt;
+ __u8 dlen;
+} __attribute__ ((packed));
+
+struct hci_h4p_neg_hdr {
+ __u8 dlen;
+} __attribute__ ((packed));
+#define H4P_NEG_HDR_SIZE 1
+
+#define H4P_NEG_REQ 0x00
+#define H4P_NEG_ACK 0x20
+#define H4P_NEG_NAK 0x40
+
+#define H4P_PROTO_PKT 0x44
+#define H4P_PROTO_BYTE 0x4c
+
+#define H4P_ID_CSR 0x02
+#define H4P_ID_BCM2048 0x04
+#define H4P_ID_TI1271 0x31
+
+struct hci_h4p_neg_cmd {
+ __u8 ack;
+ __u16 baud;
+ __u16 unused1;
+ __u8 proto;
+ __u16 sys_clk;
+ __u16 unused2;
+} __attribute__ ((packed));
+
+struct hci_h4p_neg_evt {
+ __u8 ack;
+ __u16 baud;
+ __u16 unused1;
+ __u8 proto;
+ __u16 sys_clk;
+ __u16 unused2;
+ __u8 man_id;
+ __u8 ver_id;
+} __attribute__ ((packed));
+
+#define H4P_ALIVE_REQ 0x55
+#define H4P_ALIVE_RESP 0xcc
+
+struct hci_h4p_alive_hdr {
+ __u8 dlen;
+} __attribute__ ((packed));
+#define H4P_ALIVE_HDR_SIZE 1
+
+struct hci_h4p_alive_pkt {
+ __u8 mid;
+ __u8 unused;
+} __attribute__ ((packed));
+
+#define MAX_BAUD_RATE 921600
+#define BC4_MAX_BAUD_RATE 3692300
+#define UART_CLOCK 48000000
+#define BT_INIT_DIVIDER 320
+#define BT_BAUDRATE_DIVIDER 384000000
+#define BT_SYSCLK_DIV 1000
+#define INIT_SPEED 120000
+
+#define H4_TYPE_SIZE 1
+#define H4_RADIO_HDR_SIZE 2
+
+/* H4+ packet types */
+#define H4_CMD_PKT 0x01
+#define H4_ACL_PKT 0x02
+#define H4_SCO_PKT 0x03
+#define H4_EVT_PKT 0x04
+#define H4_NEG_PKT 0x06
+#define H4_ALIVE_PKT 0x07
+#define H4_RADIO_PKT 0x08
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE 1
+#define WAIT_FOR_HEADER 2
+#define WAIT_FOR_DATA 3
+
+struct hci_fw_event {
+ struct hci_event_hdr hev;
+ struct hci_ev_cmd_complete cmd;
+ u8 status;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+void hci_h4p_init_uart(struct hci_h4p_info *info);
+void hci_h4p_enable_tx(struct hci_h4p_info *info);
+void hci_h4p_store_regs(struct hci_h4p_info *info);
+void hci_h4p_restore_regs(struct hci_h4p_info *info);
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/nokia_core.c b/drivers/bluetooth/nokia_core.c
new file mode 100644
index 0000000..d6e9b3911
--- /dev/null
+++ b/drivers/bluetooth/nokia_core.c
@@ -0,0 +1,1220 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ * Thanks to all the Nokia people that helped with this driver,
+ * including Ville Tervo and Roger Quadros.
+ *
+ * Power saving functionality was removed from this driver to make
+ * merging easier.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/kthread.h>
+#include <linux/io.h>
+#include <linux/completion.h>
+#include <linux/sizes.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include <linux/platform_data/hci-h4p.h>
+
+#include "hci_h4p.h"
+
+/* This should be used in function that cannot release clocks */
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->clocks_lock, flags);
+ if (enable && !*clock) {
+ BT_DBG("Enabling %p\n", clock);
+ clk_prepare_enable(info->uart_fclk);
+ clk_prepare_enable(info->uart_iclk);
+ if (atomic_read(&info->clk_users) == 0)
+ hci_h4p_restore_regs(info);
+ atomic_inc(&info->clk_users);
+ }
+
+ if (!enable && *clock) {
+ BT_DBG("Disabling %p\n", clock);
+ if (atomic_dec_and_test(&info->clk_users))
+ hci_h4p_store_regs(info);
+ clk_disable_unprepare(info->uart_fclk);
+ clk_disable_unprepare(info->uart_iclk);
+ }
+
+ *clock = enable;
+ spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+static void hci_h4p_lazy_clock_release(unsigned long data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ if (!info->tx_enabled)
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+/* Power management functions */
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable)
+{
+ u8 v;
+
+ v = hci_h4p_inb(info, UART_OMAP_SYSC);
+ v &= ~(UART_OMAP_SYSC_IDLEMASK);
+
+ if (enable)
+ v |= UART_OMAP_SYSC_SMART_IDLE;
+ else
+ v |= UART_OMAP_SYSC_NO_IDLE;
+
+ hci_h4p_outb(info, UART_OMAP_SYSC, v);
+}
+
+static inline void h4p_schedule_pm(struct hci_h4p_info *info)
+{
+}
+
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+ BT_DBG("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ /* Re-enable smart-idle */
+ hci_h4p_smart_idle(info, 1);
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ mod_timer(&info->lazy_release, jiffies + msecs_to_jiffies(100));
+ info->tx_enabled = 0;
+}
+
+void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+ unsigned long flags;
+ BT_DBG("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ h4p_schedule_pm(info);
+
+ spin_lock_irqsave(&info->lock, flags);
+ del_timer(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ info->tx_enabled = 1;
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ /*
+ * Disable smart-idle as UART TX interrupts
+ * are not wake-up capable
+ */
+ hci_h4p_smart_idle(info, 0);
+
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ info->rx_enabled = 0;
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)
+ return;
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+ return;
+
+ __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ info->autorts = 0;
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ h4p_schedule_pm(info);
+
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ info->rx_enabled = 1;
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+ return;
+
+ __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ info->autorts = 1;
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+ struct hci_h4p_alive_hdr *hdr;
+ struct hci_h4p_alive_pkt *pkt;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int len;
+
+ BT_DBG("Sending alive packet\n");
+
+ len = H4_TYPE_SIZE + sizeof(*hdr) + sizeof(*pkt);
+ skb = bt_skb_alloc(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0x00, len);
+ *skb_put(skb, 1) = H4_ALIVE_PKT;
+ hdr = (struct hci_h4p_alive_hdr *)skb_put(skb, sizeof(*hdr));
+ hdr->dlen = sizeof(*pkt);
+ pkt = (struct hci_h4p_alive_pkt *)skb_put(skb, sizeof(*pkt));
+ pkt->mid = H4P_ALIVE_REQ;
+
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ BT_DBG("Alive packet sent\n");
+
+ return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_h4p_alive_hdr *hdr;
+ struct hci_h4p_alive_pkt *pkt;
+
+ BT_DBG("Received alive packet\n");
+ hdr = (struct hci_h4p_alive_hdr *)skb->data;
+ if (hdr->dlen != sizeof(*pkt)) {
+ dev_err(info->dev, "Corrupted alive message\n");
+ info->init_error = -EIO;
+ goto finish_alive;
+ }
+
+ pkt = (struct hci_h4p_alive_pkt *)skb_pull(skb, sizeof(*hdr));
+ if (pkt->mid != H4P_ALIVE_RESP) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+finish_alive:
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
+{
+ struct hci_h4p_neg_cmd *neg_cmd;
+ struct hci_h4p_neg_hdr *neg_hdr;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int err, len;
+ u16 sysclk;
+
+ BT_DBG("Sending negotiation..\n");
+
+ switch (info->bt_sysclk) {
+ case 1:
+ sysclk = 12000;
+ break;
+ case 2:
+ sysclk = 38400;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ len = sizeof(*neg_cmd) + sizeof(*neg_hdr) + H4_TYPE_SIZE;
+ skb = bt_skb_alloc(len, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ memset(skb->data, 0x00, len);
+ *skb_put(skb, 1) = H4_NEG_PKT;
+ neg_hdr = (struct hci_h4p_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
+ neg_cmd = (struct hci_h4p_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
+
+ neg_hdr->dlen = sizeof(*neg_cmd);
+ neg_cmd->ack = H4P_NEG_REQ;
+ neg_cmd->baud = cpu_to_le16(BT_BAUDRATE_DIVIDER/MAX_BAUD_RATE);
+ neg_cmd->proto = H4P_PROTO_BYTE;
+ neg_cmd->sys_clk = cpu_to_le16(sysclk);
+
+ hci_h4p_change_speed(info, INIT_SPEED);
+
+ hci_h4p_set_rts(info, 1);
+ info->init_error = 0;
+ init_completion(&info->init_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ /* Change to operational settings */
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0)
+ return err;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ init_completion(&info->init_completion);
+ err = hci_h4p_send_alive_packet(info);
+
+ if (err < 0)
+ return err;
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ BT_DBG("Negotiation succesful\n");
+ return 0;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_h4p_neg_hdr *hdr;
+ struct hci_h4p_neg_evt *evt;
+
+ hdr = (struct hci_h4p_neg_hdr *)skb->data;
+ if (hdr->dlen != sizeof(*evt)) {
+ info->init_error = -EIO;
+ goto finish_neg;
+ }
+
+ evt = (struct hci_h4p_neg_evt *)skb_pull(skb, sizeof(*hdr));
+
+ if (evt->ack != H4P_NEG_ACK) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+ info->man_id = evt->man_id;
+ info->ver_id = evt->ver_id;
+
+finish_neg:
+
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = H4P_NEG_HDR_SIZE;
+ break;
+ case H4_ALIVE_PKT:
+ retval = H4P_ALIVE_HDR_SIZE;
+ break;
+ case H4_RADIO_PKT:
+ retval = H4_RADIO_HDR_SIZE;
+ break;
+ default:
+ dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_h4p_neg_hdr *neg_hdr;
+ struct hci_h4p_alive_hdr *alive_hdr;
+ struct hci_h4p_radio_hdr *radio_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_RADIO_PKT:
+ radio_hdr = (struct hci_h4p_radio_hdr *)skb->data;
+ retval = radio_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ neg_hdr = (struct hci_h4p_neg_hdr *)skb->data;
+ retval = neg_hdr->dlen;
+ break;
+ case H4_ALIVE_PKT:
+ alive_hdr = (struct hci_h4p_alive_hdr *)skb->data;
+ retval = alive_hdr->dlen;
+ break;
+ }
+
+ return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_NEG_PKT:
+ hci_h4p_negotiation_packet(info, skb);
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ return;
+ case H4_ALIVE_PKT:
+ hci_h4p_alive_packet(info, skb);
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ return;
+ }
+
+ if (!test_bit(HCI_UP, &info->hdev->flags)) {
+ BT_DBG("fw_event\n");
+ hci_h4p_parse_fw_event(info, skb);
+ return;
+ }
+ }
+
+ hci_recv_frame(info->hdev, skb);
+ BT_DBG("Frame sent to upper layer\n");
+}
+
+static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
+{
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = hci_h4p_get_hdr_len(info, byte);
+ if (info->rx_count < 0) {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ } else {
+ info->rx_state = WAIT_FOR_HEADER;
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count == 0) {
+ info->rx_count = hci_h4p_get_data_len(info,
+ info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ dev_err(info->dev, "Too long frame.\n");
+ info->garbage_bytes = info->rx_count -
+ skb_tailroom(info->rx_skb);
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+
+ }
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (info->rx_count == 0) {
+ /* H4+ devices should allways send word aligned
+ * packets */
+ if (!(info->rx_skb->len % 2))
+ info->garbage_bytes++;
+ hci_h4p_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ }
+}
+
+static void hci_h4p_rx_tasklet(unsigned long data)
+{
+ u8 byte;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ BT_DBG("tasklet woke up\n");
+ BT_DBG("rx_tasklet woke up\ndata ");
+
+ while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ byte = hci_h4p_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ continue;
+ }
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
+ GFP_ATOMIC | GFP_DMA);
+ if (!info->rx_skb) {
+ dev_err(info->dev,
+ "No memory for new packet\n");
+ goto finish_rx;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_skb->dev = (void *)info->hdev;
+ }
+ info->hdev->stat.byte_rx++;
+ pr_debug("0x%.2x ", byte);
+ hci_h4p_handle_byte(info, byte);
+ }
+
+ if (!info->rx_enabled) {
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
+ info->autorts) {
+ __hci_h4p_set_auto_ctsrts(info, 0 , UART_EFR_RTS);
+ info->autorts = 0;
+ }
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ }
+
+finish_rx:
+ pr_debug("\n");
+ BT_DBG("rx_ended\n");
+}
+
+static void hci_h4p_tx_tasklet(unsigned long data)
+{
+ unsigned int sent = 0;
+ struct sk_buff *skb;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ BT_DBG("tasklet woke up\n");
+ BT_DBG("tx_tasklet woke up\n data ");
+
+ if (info->autorts != info->rx_enabled) {
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ if (info->autorts && !info->rx_enabled) {
+ __hci_h4p_set_auto_ctsrts(info, 0,
+ UART_EFR_RTS);
+ info->autorts = 0;
+ }
+ if (!info->autorts && info->rx_enabled) {
+ __hci_h4p_set_auto_ctsrts(info, 1,
+ UART_EFR_RTS);
+ info->autorts = 1;
+ }
+ } else {
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ goto finish_tx;
+ }
+ }
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ BT_DBG("skb ready\n");
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ hci_h4p_outb(info, UART_IER,
+ hci_h4p_inb(info, UART_IER) &
+ ~UART_IER_THRI);
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_disable_tx(info);
+ return;
+ } else
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ goto finish_tx;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ pr_debug("0x%.2x ", skb->data[sent]);
+ hci_h4p_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ pr_debug("\n");
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) &
+ ~UART_OMAP_SCR_EMPTY_THR);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+
+finish_tx:
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ u8 iir, msr;
+ int ret;
+
+ ret = IRQ_NONE;
+
+ iir = hci_h4p_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return IRQ_HANDLED;
+
+ BT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = hci_h4p_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ hci_h4p_inb(info, UART_RX);
+ hci_h4p_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ hci_h4p_rx_tasklet((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ hci_h4p_tx_tasklet((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct hci_h4p_info *info = dev_inst;
+ int should_wakeup;
+ struct hci_dev *hdev;
+
+ if (!info->hdev)
+ return IRQ_HANDLED;
+
+ should_wakeup = gpio_get_value(info->host_wakeup_gpio);
+ hdev = info->hdev;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ if (should_wakeup == 1)
+ complete_all(&info->test_completion);
+
+ return IRQ_HANDLED;
+ }
+
+ BT_DBG("gpio interrupt %d\n", should_wakeup);
+
+ /* Check if wee have missed some interrupts */
+ if (info->rx_enabled == should_wakeup)
+ return IRQ_HANDLED;
+
+ if (should_wakeup)
+ hci_h4p_enable_rx(info);
+ else
+ hci_h4p_disable_rx(info);
+
+ return IRQ_HANDLED;
+}
+
+static inline void hci_h4p_set_pm_limits(struct hci_h4p_info *info, bool set)
+{
+ struct hci_h4p_platform_data *bt_plat_data = info->dev->platform_data;
+ char *sset = set ? "set" : "clear";
+
+ if (unlikely(!bt_plat_data || !bt_plat_data->set_pm_limits))
+ return;
+
+ if (set != !!test_bit(H4P_ACTIVE_MODE, &info->pm_flags)) {
+ bt_plat_data->set_pm_limits(info->dev, set);
+ if (set)
+ set_bit(H4P_ACTIVE_MODE, &info->pm_flags);
+ else
+ clear_bit(H4P_ACTIVE_MODE, &info->pm_flags);
+ BT_DBG("Change pm constraints to: %s", sset);
+ return;
+ }
+
+ BT_DBG("pm constraints remains: %s", sset);
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+ int err;
+
+ err = hci_h4p_reset_uart(info);
+ if (err < 0) {
+ dev_err(info->dev, "Uart reset failed\n");
+ return err;
+ }
+ hci_h4p_init_uart(info);
+ hci_h4p_set_rts(info, 0);
+
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ msleep(10);
+
+ if (gpio_get_value(info->host_wakeup_gpio) == 1) {
+ dev_err(info->dev, "host_wakeup_gpio not low\n");
+ return -EPROTO;
+ }
+
+ init_completion(&info->test_completion);
+ gpio_set_value(info->reset_gpio, 1);
+
+ if (!wait_for_completion_interruptible_timeout(&info->test_completion,
+ msecs_to_jiffies(100))) {
+ dev_err(info->dev, "wakeup test timed out\n");
+ complete_all(&info->test_completion);
+ return -EPROTO;
+ }
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0) {
+ dev_err(info->dev, "No cts from bt chip\n");
+ return err;
+ }
+
+ hci_h4p_set_rts(info, 1);
+
+ return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hci_get_drvdata(hdev);
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int hci_h4p_bt_wakeup_test(struct hci_h4p_info *info)
+{
+ /*
+ * Test Sequence:
+ * Host de-asserts the BT_WAKE_UP line.
+ * Host polls the UART_CTS line, waiting for it to be de-asserted.
+ * Host asserts the BT_WAKE_UP line.
+ * Host polls the UART_CTS line, waiting for it to be asserted.
+ * Host de-asserts the BT_WAKE_UP line (allow the Bluetooth device to
+ * sleep).
+ * Host polls the UART_CTS line, waiting for it to be de-asserted.
+ */
+ int err;
+ int ret = -ECOMM;
+
+ if (!info)
+ return -EINVAL;
+
+ /* Disable wakeup interrupts */
+ disable_irq(gpio_to_irq(info->host_wakeup_gpio));
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ err = hci_h4p_wait_for_cts(info, 0, 100);
+ if (err) {
+ dev_warn(info->dev, "bt_wakeup_test: fail: "
+ "CTS low timed out: %d\n", err);
+ goto out;
+ }
+
+ gpio_set_value(info->bt_wakeup_gpio, 1);
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err) {
+ dev_warn(info->dev, "bt_wakeup_test: fail: "
+ "CTS high timed out: %d\n", err);
+ goto out;
+ }
+
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ err = hci_h4p_wait_for_cts(info, 0, 100);
+ if (err) {
+ dev_warn(info->dev, "bt_wakeup_test: fail: "
+ "CTS re-low timed out: %d\n", err);
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+
+ /* Re-enable wakeup interrupts */
+ enable_irq(gpio_to_irq(info->host_wakeup_gpio));
+
+ return ret;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ int err, retries = 0;
+ struct sk_buff_head fw_queue;
+ unsigned long flags;
+
+ info = hci_get_drvdata(hdev);
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ /* TI1271 has HW bug and boot up might fail. Retry up to three times */
+again:
+
+ info->rx_enabled = 1;
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
+ init_completion(&info->fw_completion);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ skb_queue_head_init(&fw_queue);
+
+ err = hci_h4p_reset(info);
+ if (err < 0)
+ goto err_clean;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+ info->autorts = 1;
+
+ err = hci_h4p_send_negotiation(info);
+
+ err = hci_h4p_read_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Cannot read firmware\n");
+ goto err_clean;
+ }
+
+ err = hci_h4p_send_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Sending firmware failed.\n");
+ goto err_clean;
+ }
+
+ info->pm_enabled = 1;
+
+ err = hci_h4p_bt_wakeup_test(info);
+ if (err < 0) {
+ dev_err(info->dev, "BT wakeup test failed.\n");
+ goto err_clean;
+ }
+
+ spin_lock_irqsave(&info->lock, flags);
+ info->rx_enabled = gpio_get_value(info->host_wakeup_gpio);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ BT_DBG("hci up and running\n");
+ return 0;
+
+err_clean:
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_reset_uart(info);
+ del_timer_sync(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ skb_queue_purge(&fw_queue);
+ kfree_skb(info->alive_cmd_skb);
+ info->alive_cmd_skb = NULL;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+
+ if (retries++ < 3) {
+ dev_err(info->dev, "FW loading try %d fail. Retry.\n", retries);
+ goto again;
+ }
+
+ return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hci_get_drvdata(hdev);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ hci_h4p_reset_uart(info);
+ del_timer_sync(&info->lazy_release);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ gpio_set_value(info->reset_gpio, 0);
+ gpio_set_value(info->bt_wakeup_gpio, 0);
+ kfree_skb(info->rx_skb);
+
+ return 0;
+}
+
+static int hci_h4p_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_h4p_info *info;
+ int err = 0;
+
+ if (!hdev) {
+ printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+ return -ENODEV;
+ }
+
+ BT_DBG("dev %p, skb %p\n", hdev, skb);
+
+ info = hci_get_drvdata(hdev);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ dev_warn(info->dev, "Frame for non-running device\n");
+ return -EIO;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ /* Push frame type to skb */
+ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+ /* We should allways send word aligned data to h4+ devices */
+ if (skb->len % 2) {
+ err = skb_pad(skb, 1);
+ if (!err)
+ *skb_put(skb, 1) = 0x00;
+ }
+ if (err)
+ return err;
+
+ skb_queue_tail(&info->txq, skb);
+ hci_h4p_enable_tx(info);
+
+ return 0;
+}
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+ unsigned int bdaddr[6];
+ int ret, i;
+
+ ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+ &bdaddr[0], &bdaddr[1], &bdaddr[2],
+ &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+ if (ret != 6)
+ return -EINVAL;
+
+ for (i = 0; i < 6; i++)
+ info->bd_addr[i] = bdaddr[i] & 0xff;
+
+ return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%pMR\n", info->bd_addr);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr,
+ hci_h4p_store_bdaddr);
+
+static int hci_h4p_sysfs_create_files(struct device *dev)
+{
+ return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+static void hci_h4p_sysfs_remove_files(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_bdaddr);
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ dev_err(info->dev, "Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->bus = HCI_UART;
+ hci_set_drvdata(hdev, info);
+
+ hdev->open = hci_h4p_hci_open;
+ hdev->close = hci_h4p_hci_close;
+ hdev->flush = hci_h4p_hci_flush;
+ hdev->send = hci_h4p_hci_send_frame;
+ set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+ SET_HCIDEV_DEV(hdev, info->dev);
+
+ if (hci_h4p_sysfs_create_files(info->dev) < 0) {
+ dev_err(info->dev, "failed to create sysfs files\n");
+ goto free;
+ }
+
+ if (hci_register_dev(hdev) >= 0)
+ return 0;
+
+ dev_err(info->dev, "hci_register failed %s.\n", hdev->name);
+ hci_h4p_sysfs_remove_files(info->dev);
+free:
+ hci_free_dev(info->hdev);
+ return -ENODEV;
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+ struct hci_h4p_platform_data *bt_plat_data;
+ struct hci_h4p_info *info;
+ int err;
+
+ dev_info(&pdev->dev, "Registering HCI H4P device\n");
+ info = devm_kzalloc(&pdev->dev, sizeof(struct hci_h4p_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->tx_enabled = 1;
+ info->rx_enabled = 1;
+ spin_lock_init(&info->lock);
+ spin_lock_init(&info->clocks_lock);
+ skb_queue_head_init(&info->txq);
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+ return -ENODATA;
+ }
+
+ bt_plat_data = pdev->dev.platform_data;
+ info->chip_type = bt_plat_data->chip_type;
+ info->bt_wakeup_gpio = bt_plat_data->bt_wakeup_gpio;
+ info->host_wakeup_gpio = bt_plat_data->host_wakeup_gpio;
+ info->reset_gpio = bt_plat_data->reset_gpio;
+ info->reset_gpio_shared = bt_plat_data->reset_gpio_shared;
+ info->bt_sysclk = bt_plat_data->bt_sysclk;
+
+ BT_DBG("RESET gpio: %d\n", info->reset_gpio);
+ BT_DBG("BTWU gpio: %d\n", info->bt_wakeup_gpio);
+ BT_DBG("HOSTWU gpio: %d\n", info->host_wakeup_gpio);
+ BT_DBG("sysclk: %d\n", info->bt_sysclk);
+
+ init_completion(&info->test_completion);
+ complete_all(&info->test_completion);
+
+ if (!info->reset_gpio_shared) {
+ err = devm_gpio_request_one(&pdev->dev, info->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_reset");
+ if (err < 0) {
+ dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
+ info->reset_gpio);
+ return err;
+ }
+ }
+
+ err = devm_gpio_request_one(&pdev->dev, info->bt_wakeup_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_wakeup");
+
+ if (err < 0) {
+ dev_err(info->dev, "Cannot get GPIO line 0x%d",
+ info->bt_wakeup_gpio);
+ return err;
+ }
+
+ err = devm_gpio_request_one(&pdev->dev, info->host_wakeup_gpio,
+ GPIOF_DIR_IN, "host_wakeup");
+ if (err < 0) {
+ dev_err(info->dev, "Cannot get GPIO line %d",
+ info->host_wakeup_gpio);
+ return err;
+ }
+
+ info->irq = bt_plat_data->uart_irq;
+ info->uart_base = devm_ioremap(&pdev->dev, bt_plat_data->uart_base, SZ_2K);
+ info->uart_iclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_iclk);
+ info->uart_fclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_fclk);
+
+ err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED, "hci_h4p",
+ info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
+ return err;
+ }
+
+ err = devm_request_irq(&pdev->dev, gpio_to_irq(info->host_wakeup_gpio),
+ hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ "hci_h4p_wkup", info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ return err;
+ }
+
+ err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ return err;
+ }
+
+ init_timer_deferrable(&info->lazy_release);
+ info->lazy_release.function = hci_h4p_lazy_clock_release;
+ info->lazy_release.data = (unsigned long)info;
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ err = hci_h4p_reset_uart(info);
+ if (err < 0)
+ return err;
+ gpio_set_value(info->reset_gpio, 0);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ platform_set_drvdata(pdev, info);
+
+ if (hci_h4p_register_hdev(info) < 0) {
+ dev_err(info->dev, "failed to register hci_h4p hci device\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int hci_h4p_remove(struct platform_device *pdev)
+{
+ struct hci_h4p_info *info;
+
+ info = platform_get_drvdata(pdev);
+
+ hci_h4p_sysfs_remove_files(info->dev);
+ hci_h4p_hci_close(info->hdev);
+ hci_unregister_dev(info->hdev);
+ hci_free_dev(info->hdev);
+ gpio_free(info->bt_wakeup_gpio);
+ gpio_free(info->host_wakeup_gpio);
+ free_irq(info->irq, (void *) info);
+
+ return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+ .probe = hci_h4p_probe,
+ .remove = hci_h4p_remove,
+ .driver = {
+ .name = "hci_h4p",
+ },
+};
+
+module_platform_driver(hci_h4p_driver);
+
+MODULE_ALIAS("platform:hci_h4p");
+MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
+MODULE_FIRMWARE(FW_NAME_TI1271_PRELE);
+MODULE_FIRMWARE(FW_NAME_TI1271_LE);
+MODULE_FIRMWARE(FW_NAME_TI1271);
+MODULE_FIRMWARE(FW_NAME_BCM2048);
+MODULE_FIRMWARE(FW_NAME_CSR);
diff --git a/drivers/bluetooth/nokia_fw-bcm.c b/drivers/bluetooth/nokia_fw-bcm.c
new file mode 100644
index 0000000..0cf8535
--- /dev/null
+++ b/drivers/bluetooth/nokia_fw-bcm.c
@@ -0,0 +1,147 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ int i;
+ static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+ int not_valid;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+ /* When address is not valid, use some random but Nokia MAC */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ for (i = 0; i < 6; i++)
+ skb->data[9 - i] = info->bd_addr[i];
+
+ return 0;
+}
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ int err;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(info->fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
+ BT_DBG("Setting bluetooth address\n");
+ err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
+ if (err < 0) {
+ kfree_skb(fw_skb);
+ info->fw_error = err;
+ complete(&info->fw_completion);
+ return;
+ }
+ }
+
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware\n");
+
+ time = jiffies;
+
+ info->fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ BT_DBG("Sending commands\n");
+
+ /*
+ * Disable smart-idle as UART TX interrupts
+ * are not wake-up capable
+ */
+ hci_h4p_smart_idle(info, 0);
+
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(2000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ BT_DBG("Firmware sent in %d msecs\n",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/bluetooth/nokia_fw-csr.c b/drivers/bluetooth/nokia_fw-csr.c
new file mode 100644
index 0000000..0413a16
--- /dev/null
+++ b/drivers/bluetooth/nokia_fw-csr.c
@@ -0,0 +1,150 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ /* Check if this is fw packet */
+ if (skb->data[0] != 0xff) {
+ hci_recv_frame(info->hdev, skb);
+ return;
+ }
+
+ if (skb->data[11] || skb->data[12]) {
+ dev_err(info->dev, "Firmware sending command failed\n");
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+ complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
+ struct sk_buff *skb;
+ unsigned int offset;
+ int retries, count, i, not_valid;
+ unsigned long flags;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware\n");
+ skb = skb_dequeue(fw_queue);
+
+ if (!skb)
+ return -ENOMSG;
+
+ /* Check if this is bd_address packet */
+ if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+ offset = 21;
+ skb->data[offset + 1] = 0x00;
+ skb->data[offset + 5] = 0x00;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found,"
+ " setting some random\n");
+ /* When address is not valid, use some random */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ skb->data[offset + 7] = info->bd_addr[0];
+ skb->data[offset + 6] = info->bd_addr[1];
+ skb->data[offset + 4] = info->bd_addr[2];
+ skb->data[offset + 0] = info->bd_addr[3];
+ skb->data[offset + 3] = info->bd_addr[4];
+ skb->data[offset + 2] = info->bd_addr[5];
+ }
+
+ for (count = 1; ; count++) {
+ BT_DBG("Sending firmware command %d\n", count);
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ break;
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(1000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+ };
+
+ /* Wait for chip warm reset */
+ retries = 100;
+ while ((!skb_queue_empty(&info->txq) ||
+ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+ retries--) {
+ msleep(10);
+ }
+ if (!retries) {
+ dev_err(info->dev, "Transmitter not empty\n");
+ return -ETIMEDOUT;
+ }
+
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev, "cts didn't deassert after final speed\n");
+ return -ETIMEDOUT;
+ }
+
+ retries = 100;
+ do {
+ init_completion(&info->init_completion);
+ hci_h4p_send_alive_packet(info);
+ retries--;
+ } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+ retries > 0);
+
+ if (!retries) {
+ dev_err(info->dev, "No alive reply after speed change\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/bluetooth/nokia_fw-ti1273.c b/drivers/bluetooth/nokia_fw-ti1273.c
new file mode 100644
index 0000000..fd82494
--- /dev/null
+++ b/drivers/bluetooth/nokia_fw-ti1273.c
@@ -0,0 +1,110 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static struct sk_buff_head *fw_q;
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ BT_DBG("Sending firmware\n");
+
+ time = jiffies;
+
+ fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ BT_DBG("Sending commands\n");
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ hci_h4p_smart_idle(info, 0);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(2000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ BT_DBG("Firmware sent in %d msecs\n",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev,
+ "cts didn't go down after final speed change\n");
+ return -ETIMEDOUT;
+ }
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/bluetooth/nokia_fw.c b/drivers/bluetooth/nokia_fw.c
new file mode 100644
index 0000000..f69efd8
--- /dev/null
+++ b/drivers/bluetooth/nokia_fw.c
@@ -0,0 +1,195 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+ const struct firmware **fw_entry)
+{
+ int err;
+
+ fw_pos = 0;
+ BT_DBG("Opening firmware man_id 0x%.2x ver_id 0x%.2x\n",
+ info->man_id, info->ver_id);
+ switch (info->man_id) {
+ case H4P_ID_TI1271:
+ switch (info->ver_id) {
+ case 0xe1:
+ err = request_firmware(fw_entry, FW_NAME_TI1271_PRELE,
+ info->dev);
+ break;
+ case 0xd1:
+ case 0xf1:
+ err = request_firmware(fw_entry, FW_NAME_TI1271_LE,
+ info->dev);
+ break;
+ default:
+ err = request_firmware(fw_entry, FW_NAME_TI1271,
+ info->dev);
+ }
+ break;
+ case H4P_ID_CSR:
+ err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
+ break;
+ case H4P_ID_BCM2048:
+ err = request_firmware(fw_entry, FW_NAME_BCM2048, info->dev);
+ break;
+ default:
+ dev_err(info->dev, "Invalid chip type\n");
+ *fw_entry = NULL;
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+ release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+ const struct firmware *fw_entry, gfp_t how)
+{
+ unsigned int cmd_len;
+
+ if (fw_pos >= fw_entry->size)
+ return 0;
+
+ if (fw_pos + 2 > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 1\n");
+ return -EMSGSIZE;
+ }
+
+ cmd_len = fw_entry->data[fw_pos++];
+ cmd_len += fw_entry->data[fw_pos++] << 8;
+ if (cmd_len == 0)
+ return 0;
+
+ if (fw_pos + cmd_len > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 2\n");
+ return -EMSGSIZE;
+ }
+
+ *skb = bt_skb_alloc(cmd_len, how);
+ if (!*skb) {
+ dev_err(info->dev, "Cannot reserve memory for buffer\n");
+ return -ENOMEM;
+ }
+ memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+ fw_pos += cmd_len;
+
+ return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ const struct firmware *fw_entry = NULL;
+ struct sk_buff *skb = NULL;
+ int err;
+
+ err = hci_h4p_open_firmware(info, &fw_entry);
+ if (err < 0 || !fw_entry)
+ goto err_clean;
+
+ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+ if (err < 0 || !skb)
+ goto err_clean;
+
+ skb_queue_tail(fw_queue, skb);
+ }
+
+ /* Chip detection code does neg and alive stuff
+ * discard two first skbs */
+ skb = skb_dequeue(fw_queue);
+ if (!skb) {
+ err = -EMSGSIZE;
+ goto err_clean;
+ }
+ kfree_skb(skb);
+ skb = skb_dequeue(fw_queue);
+ if (!skb) {
+ err = -EMSGSIZE;
+ goto err_clean;
+ }
+ kfree_skb(skb);
+
+err_clean:
+ hci_h4p_close_firmware(fw_entry);
+ return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ int err;
+
+ switch (info->man_id) {
+ case H4P_ID_CSR:
+ err = hci_h4p_bc4_send_fw(info, fw_queue);
+ break;
+ case H4P_ID_TI1271:
+ err = hci_h4p_ti1273_send_fw(info, fw_queue);
+ break;
+ case H4P_ID_BCM2048:
+ err = hci_h4p_bcm_send_fw(info, fw_queue);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to send firmware\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ switch (info->man_id) {
+ case H4P_ID_CSR:
+ hci_h4p_bc4_parse_fw_event(info, skb);
+ break;
+ case H4P_ID_TI1271:
+ hci_h4p_ti1273_parse_fw_event(info, skb);
+ break;
+ case H4P_ID_BCM2048:
+ hci_h4p_bcm_parse_fw_event(info, skb);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to parse fw event\n");
+ info->fw_error = -EINVAL;
+ }
+
+ return;
+}
diff --git a/drivers/bluetooth/nokia_uart.c b/drivers/bluetooth/nokia_uart.c
new file mode 100644
index 0000000..c19b8d2
--- /dev/null
+++ b/drivers/bluetooth/nokia_uart.c
@@ -0,0 +1,199 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <linux/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+ __raw_writeb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+ return __raw_readb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+ u8 b;
+
+ b = hci_h4p_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+ int timeout_ms)
+{
+ unsigned long timeout;
+ int state;
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ return 0;
+ } else {
+ if (!state)
+ return 0;
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ msleep(1);
+ }
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ u8 lcr, b;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ b = hci_h4p_inb(info, UART_EFR);
+ if (on)
+ b |= which;
+ else
+ b &= ~which;
+ hci_h4p_outb(info, UART_EFR, b);
+ hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ __hci_h4p_set_auto_ctsrts(info, on, which);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ BT_DBG("Setting speed %lu\n", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ /* Make sure UART mode is disabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ hci_h4p_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, divisor >> 8);
+ hci_h4p_outb(info, UART_LCR, lcr);
+
+ /* Make sure UART mode is enabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+void hci_h4p_store_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ info->dll = hci_h4p_inb(info, UART_DLL);
+ info->dlh = hci_h4p_inb(info, UART_DLM);
+ info->efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
+ info->ier = hci_h4p_inb(info, UART_IER);
+}
+
+void hci_h4p_restore_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ hci_h4p_init_uart(info);
+
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ hci_h4p_outb(info, UART_DLL, info->dll); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, info->dlh);
+ hci_h4p_outb(info, UART_EFR, info->efr);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
+ hci_h4p_outb(info, UART_IER, info->ier);
+}
+
+void hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+ u8 mcr, efr;
+
+ /* Enable and setup FIFO */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
+
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ mcr = hci_h4p_inb(info, UART_MCR);
+ hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+ hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ (3 << 6) | (0 << 4));
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ hci_h4p_outb(info, UART_TI752_TLR, 0xed);
+ hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+ hci_h4p_outb(info, UART_EFR, efr);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ hci_h4p_outb(info, UART_MCR, 0x00);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+ hci_h4p_outb(info, UART_IER, UART_IER_RDI);
+ hci_h4p_outb(info, UART_OMAP_SYSC, (1 << 0) | (1 << 2) | (2 << 3));
+}
diff --git a/include/linux/platform_data/hci-h4p.h b/include/linux/platform_data/hci-h4p.h
new file mode 100644
index 0000000..30d169d
--- /dev/null
+++ b/include/linux/platform_data/hci-h4p.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of Nokia H4P bluetooth driver
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+/**
+ * struct hci_h4p_platform data - hci_h4p Platform data structure
+ */
+struct hci_h4p_platform_data {
+ int chip_type;
+ int bt_sysclk;
+ unsigned int bt_wakeup_gpio;
+ unsigned int host_wakeup_gpio;
+ unsigned int reset_gpio;
+ int reset_gpio_shared;
+ unsigned int uart_irq;
+ phys_addr_t uart_base;
+ const char *uart_iclk;
+ const char *uart_fclk;
+ void (*set_pm_limits)(struct device *dev, bool set);
+};
diff --git a/include/linux/platform_data/ssi.h b/include/linux/platform_data/ssi.h
new file mode 100644
index 0000000..eb84c3a
--- /dev/null
+++ b/include/linux/platform_data/ssi.h
@@ -0,0 +1,204 @@
+/*
+ * plat/ssi.h
+ *
+ * Hardware definitions for SSI.
+ *
+ * Copyright (C) 2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Carlos Chinea <carlos.chinea@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __OMAP_SSI_REGS_H__
+#define __OMAP_SSI_REGS_H__
+
+#define SSI_NUM_PORTS 1
+/*
+ * SSI SYS registers
+ */
+#define SSI_REVISION_REG 0
+# define SSI_REV_MAJOR 0xf0
+# define SSI_REV_MINOR 0xf
+#define SSI_SYSCONFIG_REG 0x10
+# define SSI_AUTOIDLE (1 << 0)
+# define SSI_SOFTRESET (1 << 1)
+# define SSI_SIDLEMODE_FORCE 0
+# define SSI_SIDLEMODE_NO (1 << 3)
+# define SSI_SIDLEMODE_SMART (1 << 4)
+# define SSI_SIDLEMODE_MASK 0x18
+# define SSI_MIDLEMODE_FORCE 0
+# define SSI_MIDLEMODE_NO (1 << 12)
+# define SSI_MIDLEMODE_SMART (1 << 13)
+# define SSI_MIDLEMODE_MASK 0x3000
+#define SSI_SYSSTATUS_REG 0x14
+# define SSI_RESETDONE 1
+#define SSI_MPU_STATUS_REG(port, irq) (0x808 + ((port) * 0x10) + ((irq) * 2))
+#define SSI_MPU_ENABLE_REG(port, irq) (0x80c + ((port) * 0x10) + ((irq) * 8))
+# define SSI_DATAACCEPT(channel) (1 << (channel))
+# define SSI_DATAAVAILABLE(channel) (1 << ((channel) + 8))
+# define SSI_DATAOVERRUN(channel) (1 << ((channel) + 16))
+# define SSI_ERROROCCURED (1 << 24)
+# define SSI_BREAKDETECTED (1 << 25)
+#define SSI_GDD_MPU_IRQ_STATUS_REG 0x0800
+#define SSI_GDD_MPU_IRQ_ENABLE_REG 0x0804
+# define SSI_GDD_LCH(channel) (1 << (channel))
+#define SSI_WAKE_REG(port) (0xc00 + ((port) * 0x10))
+#define SSI_CLEAR_WAKE_REG(port) (0xc04 + ((port) * 0x10))
+#define SSI_SET_WAKE_REG(port) (0xc08 + ((port) * 0x10))
+# define SSI_WAKE(channel) (1 << (channel))
+# define SSI_WAKE_MASK 0xff
+
+/*
+ * SSI SST registers
+ */
+#define SSI_SST_ID_REG 0
+#define SSI_SST_MODE_REG 4
+# define SSI_MODE_VAL_MASK 3
+# define SSI_MODE_SLEEP 0
+# define SSI_MODE_STREAM 1
+# define SSI_MODE_FRAME 2
+# define SSI_MODE_MULTIPOINTS 3
+#define SSI_SST_FRAMESIZE_REG 8
+# define SSI_FRAMESIZE_DEFAULT 31
+#define SSI_SST_TXSTATE_REG 0xc
+# define SSI_TXSTATE_IDLE 0
+#define SSI_SST_BUFSTATE_REG 0x10
+# define SSI_FULL(channel) (1 << (channel))
+#define SSI_SST_DIVISOR_REG 0x18
+# define SSI_MAX_DIVISOR 127
+#define SSI_SST_BREAK_REG 0x20
+#define SSI_SST_CHANNELS_REG 0x24
+# define SSI_CHANNELS_DEFAULT 4
+#define SSI_SST_ARBMODE_REG 0x28
+# define SSI_ARBMODE_ROUNDROBIN 0
+# define SSI_ARBMODE_PRIORITY 1
+#define SSI_SST_BUFFER_CH_REG(channel) (0x80 + ((channel) * 4))
+#define SSI_SST_SWAPBUF_CH_REG(channel) (0xc0 + ((channel) * 4))
+
+/*
+ * SSI SSR registers
+ */
+#define SSI_SSR_ID_REG 0
+#define SSI_SSR_MODE_REG 4
+#define SSI_SSR_FRAMESIZE_REG 8
+#define SSI_SSR_RXSTATE_REG 0xc
+#define SSI_SSR_BUFSTATE_REG 0x10
+# define SSI_NOTEMPTY(channel) (1 << (channel))
+#define SSI_SSR_BREAK_REG 0x1c
+#define SSI_SSR_ERROR_REG 0x20
+#define SSI_SSR_ERRORACK_REG 0x24
+#define SSI_SSR_OVERRUN_REG 0x2c
+#define SSI_SSR_OVERRUNACK_REG 0x30
+#define SSI_SSR_TIMEOUT_REG 0x34
+# define SSI_TIMEOUT_DEFAULT 0
+#define SSI_SSR_CHANNELS_REG 0x28
+#define SSI_SSR_BUFFER_CH_REG(channel) (0x80 + ((channel) * 4))
+#define SSI_SSR_SWAPBUF_CH_REG(channel) (0xc0 + ((channel) * 4))
+
+/*
+ * SSI GDD registers
+ */
+#define SSI_GDD_HW_ID_REG 0
+#define SSI_GDD_PPORT_ID_REG 0x10
+#define SSI_GDD_MPORT_ID_REG 0x14
+#define SSI_GDD_PPORT_SR_REG 0x20
+#define SSI_GDD_MPORT_SR_REG 0x24
+# define SSI_ACTIVE_LCH_NUM_MASK 0xff
+#define SSI_GDD_TEST_REG 0x40
+# define SSI_TEST 1
+#define SSI_GDD_GCR_REG 0x100
+# define SSI_CLK_AUTOGATING_ON (1 << 3)
+# define SSI_FREE (1 << 2)
+# define SSI_SWITCH_OFF (1 << 0)
+#define SSI_GDD_GRST_REG 0x200
+# define SSI_SWRESET 1
+#define SSI_GDD_CSDP_REG(channel) (0x800 + ((channel) * 0x40))
+# define SSI_DST_BURST_EN_MASK 0xc000
+# define SSI_DST_SINGLE_ACCESS0 0
+# define SSI_DST_SINGLE_ACCESS (1 << 14)
+# define SSI_DST_BURST_4x32_BIT (2 << 14)
+# define SSI_DST_BURST_8x32_BIT (3 << 14)
+# define SSI_DST_MASK 0x1e00
+# define SSI_DST_MEMORY_PORT (8 << 9)
+# define SSI_DST_PERIPHERAL_PORT (9 << 9)
+# define SSI_SRC_BURST_EN_MASK 0x180
+# define SSI_SRC_SINGLE_ACCESS0 0
+# define SSI_SRC_SINGLE_ACCESS (1 << 7)
+# define SSI_SRC_BURST_4x32_BIT (2 << 7)
+# define SSI_SRC_BURST_8x32_BIT (3 << 7)
+# define SSI_SRC_MASK 0x3c
+# define SSI_SRC_MEMORY_PORT (8 << 2)
+# define SSI_SRC_PERIPHERAL_PORT (9 << 2)
+# define SSI_DATA_TYPE_MASK 3
+# define SSI_DATA_TYPE_S32 2
+#define SSI_GDD_CCR_REG(channel) (0x802 + ((channel) * 0x40))
+# define SSI_DST_AMODE_MASK (3 << 14)
+# define SSI_DST_AMODE_CONST 0
+# define SSI_DST_AMODE_POSTINC (1 << 12)
+# define SSI_SRC_AMODE_MASK (3 << 12)
+# define SSI_SRC_AMODE_CONST 0
+# define SSI_SRC_AMODE_POSTINC (1 << 12)
+# define SSI_CCR_ENABLE (1 << 7)
+# define SSI_CCR_SYNC_MASK 0x1f
+#define SSI_GDD_CICR_REG(channel) (0x804 + ((channel) * 0x40))
+# define SSI_BLOCK_IE (1 << 5)
+# define SSI_HALF_IE (1 << 2)
+# define SSI_TOUT_IE (1 << 0)
+#define SSI_GDD_CSR_REG(channel) (0x806 + ((channel) * 0x40))
+# define SSI_CSR_SYNC (1 << 6)
+# define SSI_CSR_BLOCK (1 << 5)
+# define SSI_CSR_HALF (1 << 2)
+# define SSI_CSR_TOUR (1 << 0)
+#define SSI_GDD_CSSA_REG(channel) (0x808 + ((channel) * 0x40))
+#define SSI_GDD_CDSA_REG(channel) (0x80c + ((channel) * 0x40))
+#define SSI_GDD_CEN_REG(channel) (0x810 + ((channel) * 0x40))
+#define SSI_GDD_CSAC_REG(channel) (0x818 + ((channel) * 0x40))
+#define SSI_GDD_CDAC_REG(channel) (0x81a + ((channel) * 0x40))
+#define SSI_GDD_CLNK_CTRL_REG(channel) (0x828 + ((channel) * 0x40))
+# define SSI_ENABLE_LNK (1 << 15)
+# define SSI_STOP_LNK (1 << 14)
+# define SSI_NEXT_CH_ID_MASK 0xf
+
+/**
+ * struct omap_ssi_platform_data - OMAP SSI platform data
+ * @num_ports: Number of ports on the controller
+ * @ctxt_loss_count: Pointer to omap_pm_get_dev_context_loss_count
+ */
+struct omap_ssi_platform_data {
+ unsigned int num_ports;
+ int (*get_dev_context_loss_count)(struct device *dev);
+};
+
+/**
+ * struct omap_ssi_config - SSI board configuration
+ * @num_ports: Number of ports in use
+ * @cawake_line: Array of cawake gpio lines
+ */
+struct omap_ssi_board_config {
+ unsigned int num_ports;
+ int cawake_gpio[SSI_NUM_PORTS];
+};
+
+#ifdef CONFIG_OMAP_SSI_CONFIG
+extern int omap_ssi_config(struct omap_ssi_board_config *ssi_config);
+#else
+static inline int omap_ssi_config(struct omap_ssi_board_config *ssi_config)
+{
+ return 0;
+}
+#endif /* CONFIG_OMAP_SSI_CONFIG */
+
+#endif /* __OMAP_SSI_REGS_H__ */
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related
* Re: [PATCH v4] Bluetooth: Add hci_h4p driver
From: Pavel Machek @ 2014-01-10 14:49 UTC (permalink / raw)
To: Marcel Holtmann, Pali Rohár,
Ивайло Димитров,
Gustavo F. Padovan, Johan Hedberg, linux-kernel,
linux-bluetooth@vger.kernel.org development, Ville Tervo
In-Reply-To: <20140110134426.GA7235@earth.universe>
Hi!
> You have missed some things. See inline comments below.
Ok, I've done this, it should fix the rest.
diff --git a/drivers/bluetooth/nokia_core.c b/drivers/bluetooth/nokia_core.c
index d6e9b3911..6615939 100644
--- a/drivers/bluetooth/nokia_core.c
+++ b/drivers/bluetooth/nokia_core.c
@@ -1138,8 +1138,8 @@ static int hci_h4p_probe(struct platform_device *pdev)
info->uart_iclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_iclk);
info->uart_fclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_fclk);
- err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED, "hci_h4p",
- info);
+ err = devm_request_irq(&pdev->dev, info->irq, hci_h4p_interrupt, IRQF_DISABLED,
+ "hci_h4p", info);
if (err < 0) {
dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
return err;
@@ -1192,9 +1192,6 @@ static int hci_h4p_remove(struct platform_device *pdev)
hci_h4p_hci_close(info->hdev);
hci_unregister_dev(info->hdev);
hci_free_dev(info->hdev);
- gpio_free(info->bt_wakeup_gpio);
- gpio_free(info->host_wakeup_gpio);
- free_irq(info->irq, (void *) info);
return 0;
}
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related
* [PATCH v3] android/tester: Multi property check for test case
From: Grzegorz Kolodziejczyk @ 2014-01-10 14:21 UTC (permalink / raw)
To: linux-bluetooth
This patch allows to check multiple properties for test case. Properties
can be prioritized to allow check if they'll come in right order. Now
properties aren't treated as a "single" callback. In future in one
callback multiple properties can come.
---
android/android-tester.c | 536 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 392 insertions(+), 144 deletions(-)
diff --git a/android/android-tester.c b/android/android-tester.c
index 0185f99..6f18e5c 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -43,13 +43,19 @@
#include "utils.h"
+struct priority_property {
+ bt_property_t prop;
+ int prio;
+};
+
struct generic_data {
int expected_adapter_status;
uint32_t expect_settings_set;
int expected_cb_count;
bt_property_t set_property;
- bt_property_t expected_property;
bt_callbacks_t expected_hal_cb;
+ struct priority_property *expected_properties;
+ uint8_t expected_properties_num;
};
struct socket_data {
@@ -91,6 +97,7 @@ struct test_data {
bool test_init_done;
int cb_count;
+ GSList *expected_properties_list;
};
static char exec_dir[PATH_MAX + 1];
@@ -185,9 +192,18 @@ static void expected_status_init(struct test_data *data)
static void test_property_init(struct test_data *data)
{
const struct generic_data *test_data = data->test_data;
+ GSList *l = data->expected_properties_list;
+ int i;
- if (!test_data->expected_property.type)
+ if (!test_data->expected_hal_cb.adapter_properties_cb) {
data->property_checked = true;
+ return;
+ }
+
+ for (i = 0; i < test_data->expected_properties_num; i++)
+ l = g_slist_prepend(l, &(test_data->expected_properties[i]));
+
+ data->expected_properties_list = l;
}
static void init_test_conditions(struct test_data *data)
@@ -212,6 +228,75 @@ static void check_expected_status(uint8_t status)
tester_test_failed();
}
+static int locate_property(gconstpointer expected_data,
+ gconstpointer received_prop)
+{
+ bt_property_t rec_prop = *((bt_property_t *)received_prop);
+ bt_property_t exp_prop =
+ ((struct priority_property *)expected_data)->prop;
+
+ if (exp_prop.type && (exp_prop.type != rec_prop.type))
+ return 1;
+ if (exp_prop.len && (exp_prop.len != rec_prop.len))
+ return 1;
+ if (exp_prop.val && memcmp(exp_prop.val, rec_prop.val, exp_prop.len))
+ return 1;
+
+ return 0;
+}
+
+static int compare_priorities(gconstpointer prop_list, gconstpointer priority)
+{
+ int prio = GPOINTER_TO_INT(priority);
+ int comp_prio = ((struct priority_property *)prop_list)->prio;
+
+ if (prio > comp_prio)
+ return 0;
+
+ return 1;
+}
+
+static bool check_prop_priority(int rec_prop_prio)
+{
+ struct test_data *data = tester_get_data();
+ GSList *l = data->expected_properties_list;
+
+ if (!rec_prop_prio || !g_slist_length(l))
+ return true;
+
+ if (g_slist_find_custom(l, GINT_TO_POINTER(rec_prop_prio),
+ &compare_priorities))
+ return false;
+
+ return true;
+}
+
+static void check_expected_property(bt_property_t received_prop)
+{
+ struct test_data *data = tester_get_data();
+ int rec_prio;
+ GSList *l = data->expected_properties_list;
+ GSList *found_exp_prop;
+
+ found_exp_prop = g_slist_find_custom(l, &received_prop,
+ &locate_property);
+
+ if (found_exp_prop) {
+ rec_prio = ((struct priority_property *)
+ (found_exp_prop->data))->prio;
+ if (check_prop_priority(rec_prio))
+ l = g_slist_remove(l, found_exp_prop->data);
+ }
+
+ data->expected_properties_list = l;
+
+ if (g_slist_length(l))
+ return;
+
+ data->property_checked = true;
+ test_update_state();
+}
+
static bool check_test_property(bt_property_t received_prop,
bt_property_t expected_prop)
{
@@ -625,27 +710,18 @@ static void device_found_cb(int num_properties, bt_property_t *properties)
if (data->test_init_done && test->expected_hal_cb.device_found_cb) {
test->expected_hal_cb.device_found_cb(num_properties,
properties);
- check_cb_count();
}
}
static void check_count_properties_cb(bt_status_t status, int num_properties,
bt_property_t *properties)
{
- struct test_data *data = tester_get_data();
+ int i;
- data->cb_count--;
+ for (i = 0; i < num_properties; i++)
+ check_expected_property(properties[i]);
}
-static void getprop_success_cb(bt_status_t status, int num_properties,
- bt_property_t *properties)
-{
- struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
-
- if (check_test_property(properties[0], test->expected_property))
- data->cb_count--;
-}
static void adapter_properties_cb(bt_status_t status, int num_properties,
bt_property_t *properties)
@@ -658,21 +734,84 @@ static void adapter_properties_cb(bt_status_t status, int num_properties,
test->expected_hal_cb.adapter_properties_cb(
status, num_properties,
properties);
- check_cb_count();
}
}
+static bt_bdaddr_t enable_done_bdaddr_val = { {0x00} };
+static const char enable_done_bdname_val[] = "BlueZ for Android";
+static bt_uuid_t enable_done_uuids_val = {
+ .uu = { 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
+ 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb},
+};
+static bt_device_type_t enable_done_tod_val = BT_DEVICE_DEVTYPE_BREDR;
+static bt_scan_mode_t enable_done_scanmode_val = BT_SCAN_MODE_NONE;
+static uint32_t enable_done_disctimeout_val = 120;
+
+static struct priority_property enable_done_props[] = {
+ {
+ .prop.type = BT_PROPERTY_BDADDR,
+ .prop.len = sizeof(enable_done_bdaddr_val),
+ .prop.val = &enable_done_bdaddr_val,
+ .prio = 1,
+ },
+ {
+ .prop.type = BT_PROPERTY_BDNAME,
+ .prop.len = sizeof(enable_done_bdname_val) - 1,
+ .prop.val = &enable_done_bdname_val,
+ .prio = 2,
+ },
+ {
+ .prop.type = BT_PROPERTY_UUIDS,
+ .prop.len = sizeof(enable_done_uuids_val),
+ .prop.val = &enable_done_uuids_val,
+ .prio = 3,
+ },
+ {
+ .prop.type = BT_PROPERTY_CLASS_OF_DEVICE,
+ .prop.len = sizeof(uint32_t),
+ .prop.val = NULL,
+ .prio = 4,
+ },
+ {
+ .prop.type = BT_PROPERTY_TYPE_OF_DEVICE,
+ .prop.len = sizeof(enable_done_tod_val),
+ .prop.val = &enable_done_tod_val,
+ .prio = 5,
+ },
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
+ .prop.len = sizeof(enable_done_scanmode_val),
+ .prop.val = &enable_done_scanmode_val,
+ .prio = 6,
+ },
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ .prop.len = 0,
+ .prop.val = NULL,
+ .prio = 7,
+ },
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ .prop.len = sizeof(enable_done_disctimeout_val),
+ .prop.val = &enable_done_disctimeout_val,
+ .prio = 8,
+ },
+};
+
static const struct generic_data bluetooth_enable_success_test = {
.expected_hal_cb.adapter_state_changed_cb = enable_success_cb,
.expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
- .expected_cb_count = 9,
+ .expected_cb_count = 1,
+ .expected_properties_num = 8,
+ .expected_properties = enable_done_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
};
static const struct generic_data bluetooth_enable_done_test = {
.expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
- .expected_cb_count = 8,
.expected_adapter_status = BT_STATUS_DONE,
+ .expected_properties_num = 8,
+ .expected_properties = enable_done_props,
};
static const struct generic_data bluetooth_disable_success_test = {
@@ -683,94 +822,146 @@ static const struct generic_data bluetooth_disable_success_test = {
static char test_set_bdname[] = "test_bdname_set";
+static struct priority_property setprop_bdname_props[] = {
+ {
+ .prop.type = BT_PROPERTY_BDNAME,
+ .prop.val = test_set_bdname,
+ .prop.len = sizeof(test_set_bdname) - 1,
+ .prio = 0,
+ },
+};
+
static const struct generic_data bluetooth_setprop_bdname_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
- .expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_BDNAME,
- .expected_property.val = test_set_bdname,
- .expected_property.len = sizeof(test_set_bdname) - 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = setprop_bdname_props,
};
static bt_scan_mode_t test_setprop_scanmode_val =
BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE;
+static struct priority_property setprop_scanmode_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
+ .prop.val = &test_setprop_scanmode_val,
+ .prop.len = sizeof(bt_scan_mode_t),
+ },
+};
+
static const struct generic_data bluetooth_setprop_scanmode_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = setprop_scanmode_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
- .expected_property.val = &test_setprop_scanmode_val,
- .expected_property.len = sizeof(bt_scan_mode_t),
};
static uint32_t test_setprop_disctimeout_val = 120;
+static struct priority_property setprop_disctimeout_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ .prop.val = &test_setprop_disctimeout_val,
+ .prop.len = sizeof(test_setprop_disctimeout_val),
+ },
+};
+
static const struct generic_data bluetooth_setprop_disctimeout_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = setprop_disctimeout_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
- .expected_property.val = &test_setprop_disctimeout_val,
- .expected_property.len = sizeof(test_setprop_disctimeout_val),
+};
+
+static bt_bdaddr_t test_getprop_bdaddr_val = { {0x00} };
+
+static struct priority_property getprop_bdaddr_props[] = {
+ {
+ .prop.type = BT_PROPERTY_BDADDR,
+ .prop.val = &test_getprop_bdaddr_val,
+ .prop.len = sizeof(test_getprop_bdaddr_val),
+ },
};
static const struct generic_data bluetooth_getprop_bdaddr_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_bdaddr_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_BDADDR,
- .expected_property.val = NULL,
- .expected_property.len = sizeof(bt_bdaddr_t),
};
static char test_bdname[] = "test_bdname_setget";
+static struct priority_property getprop_bdname_props[] = {
+ {
+ .prop.type = BT_PROPERTY_BDNAME,
+ .prop.val = &test_bdname,
+ .prop.len = sizeof(test_bdname) - 1,
+ },
+};
+
static const struct generic_data bluetooth_getprop_bdname_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_bdname_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_BDNAME,
- .expected_property.val = test_bdname,
- .expected_property.len = sizeof(test_bdname) - 1,
};
static unsigned char setprop_uuids[] = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00,
0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00 };
+static struct priority_property setprop_uuid_prop[] = {
+ {
+ .prop.type = BT_PROPERTY_UUIDS,
+ .prop.val = &setprop_uuids,
+ .prop.len = sizeof(setprop_uuids),
+ },
+};
+
static const struct generic_data bluetooth_setprop_uuid_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_UUIDS,
- .set_property.val = &setprop_uuids,
- .set_property.len = sizeof(setprop_uuids),
};
static uint32_t setprop_class_of_device = 0;
+static struct priority_property setprop_cod_props[] = {
+ {
+ .prop.type = BT_PROPERTY_CLASS_OF_DEVICE,
+ .prop.val = &setprop_class_of_device,
+ .prop.len = sizeof(setprop_class_of_device),
+ },
+};
+
static const struct generic_data bluetooth_setprop_cod_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_CLASS_OF_DEVICE,
- .set_property.val = &setprop_class_of_device,
- .set_property.len = sizeof(setprop_class_of_device),
};
static bt_device_type_t setprop_type_of_device = BT_DEVICE_DEVTYPE_BREDR;
+static struct priority_property setprop_tod_props[] = {
+ {
+ .prop.type = BT_PROPERTY_TYPE_OF_DEVICE,
+ .prop.val = &setprop_type_of_device,
+ .prop.len = sizeof(setprop_type_of_device),
+ },
+};
+
static const struct generic_data bluetooth_setprop_tod_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_TYPE_OF_DEVICE,
- .set_property.val = &setprop_type_of_device,
- .set_property.len = sizeof(setprop_type_of_device),
};
static int32_t setprop_remote_rssi = 0;
+static struct priority_property setprop_remote_rssi_props[] = {
+ {
+ .prop.type = BT_PROPERTY_REMOTE_RSSI,
+ .prop.val = &setprop_remote_rssi,
+ .prop.len = sizeof(setprop_remote_rssi),
+ },
+};
+
static const struct generic_data bluetooth_setprop_remote_rssi_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_REMOTE_RSSI,
- .set_property.val = &setprop_remote_rssi,
- .set_property.len = sizeof(setprop_remote_rssi),
};
static bt_service_record_t setprop_remote_service = {
@@ -779,91 +970,136 @@ static bt_service_record_t setprop_remote_service = {
.name = "bt_name",
};
+static struct priority_property setprop_service_record_props[] = {
+ {
+ .prop.type = BT_PROPERTY_SERVICE_RECORD,
+ .prop.val = &setprop_remote_service,
+ .prop.len = sizeof(setprop_remote_service),
+ },
+};
+
static const struct generic_data
bluetooth_setprop_service_record_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_SERVICE_RECORD,
- .set_property.val = &setprop_remote_service,
- .set_property.len = sizeof(setprop_remote_service),
};
static bt_bdaddr_t setprop_bdaddr = {
.address = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
};
+static struct priority_property setprop_bdaddr_props[] = {
+ {
+ .prop.type = BT_PROPERTY_BDADDR,
+ .prop.val = &setprop_bdaddr,
+ .prop.len = sizeof(setprop_bdaddr),
+ },
+};
+
static const struct generic_data bluetooth_setprop_bdaddr_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_BDADDR,
- .set_property.val = &setprop_bdaddr,
- .set_property.len = sizeof(setprop_bdaddr),
};
static bt_scan_mode_t setprop_scanmode_connectable = BT_SCAN_MODE_CONNECTABLE;
+static struct priority_property setprop_scanmode_connectable_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
+ .prop.val = &setprop_scanmode_connectable,
+ .prop.len = sizeof(setprop_scanmode_connectable),
+ },
+};
+
static const struct generic_data
bluetooth_setprop_scanmode_connectable_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = setprop_scanmode_connectable_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
- .expected_property.val = &setprop_scanmode_connectable,
- .expected_property.len = sizeof(setprop_scanmode_connectable),
};
static bt_bdaddr_t setprop_bonded_devices = {
.address = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 },
};
+static struct priority_property setprop_bonded_devices_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ .prop.val = &setprop_bonded_devices,
+ .prop.len = sizeof(setprop_bonded_devices),
+ },
+};
+
static const struct generic_data
bluetooth_setprop_bonded_devices_invalid_test = {
.expected_adapter_status = BT_STATUS_FAIL,
- .set_property.type = BT_PROPERTY_ADAPTER_BONDED_DEVICES,
- .set_property.val = &setprop_bonded_devices,
- .set_property.len = sizeof(setprop_bonded_devices),
};
static uint32_t getprop_cod = 0x00020c;
+static struct priority_property getprop_cod_props[] = {
+ {
+ .prop.type = BT_PROPERTY_CLASS_OF_DEVICE,
+ .prop.val = &getprop_cod,
+ .prop.len = sizeof(getprop_cod),
+ },
+};
+
static const struct generic_data bluetooth_getprop_cod_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_cod_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_CLASS_OF_DEVICE,
- .expected_property.val = &getprop_cod,
- .expected_property.len = sizeof(getprop_cod),
};
static bt_device_type_t getprop_tod = BT_DEVICE_DEVTYPE_BREDR;
+static struct priority_property getprop_tod_props[] = {
+ {
+ .prop.type = BT_PROPERTY_TYPE_OF_DEVICE,
+ .prop.val = &getprop_tod,
+ .prop.len = sizeof(getprop_tod),
+ },
+};
+
static const struct generic_data bluetooth_getprop_tod_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_tod_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_TYPE_OF_DEVICE,
- .expected_property.val = &getprop_tod,
- .expected_property.len = sizeof(getprop_tod),
};
static bt_scan_mode_t getprop_scanmode = BT_SCAN_MODE_NONE;
+static struct priority_property getprop_scanmode_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
+ .prop.val = &getprop_scanmode,
+ .prop.len = sizeof(getprop_scanmode),
+ },
+};
+
static const struct generic_data bluetooth_getprop_scanmode_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_scanmode_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
- .expected_property.val = &getprop_scanmode,
- .expected_property.len = sizeof(getprop_scanmode),
};
static uint32_t getprop_disctimeout_val = 120;
+static struct priority_property getprop_disctimeout_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
+ .prop.val = &getprop_disctimeout_val,
+ .prop.len = sizeof(getprop_disctimeout_val),
+ },
+};
+
static const struct generic_data bluetooth_getprop_disctimeout_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_disctimeout_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT,
- .expected_property.val = &getprop_disctimeout_val,
- .expected_property.len = sizeof(getprop_disctimeout_val),
};
static bt_uuid_t getprop_uuids = {
@@ -871,33 +1107,51 @@ static bt_uuid_t getprop_uuids = {
0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB },
};
+static struct priority_property getprop_uuids_props[] = {
+ {
+ .prop.type = BT_PROPERTY_UUIDS,
+ .prop.val = &getprop_uuids,
+ .prop.len = sizeof(getprop_uuids),
+ },
+};
+
static const struct generic_data bluetooth_getprop_uuids_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_uuids_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_UUIDS,
- .expected_property.val = &getprop_uuids,
- .expected_property.len = sizeof(getprop_uuids),
+};
+
+static struct priority_property getprop_bondeddev_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_BONDED_DEVICES,
+ .prop.val = NULL,
+ .prop.len = 0,
+ },
};
static const struct generic_data bluetooth_getprop_bondeddev_success_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = getprop_bondeddev_props,
.expected_adapter_status = BT_STATUS_SUCCESS,
- .expected_property.type = BT_PROPERTY_ADAPTER_BONDED_DEVICES,
- .expected_property.val = NULL,
- .expected_property.len = 0,
};
static bt_scan_mode_t setprop_scanmode_none = BT_SCAN_MODE_NONE;
+static struct priority_property setprop_scanmode_none_props[] = {
+ {
+ .prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
+ .prop.val = &setprop_scanmode_none,
+ .prop.len = sizeof(setprop_scanmode_none),
+ },
+};
+
static const struct generic_data bluetooth_setprop_scanmode_none_done_test = {
- .expected_hal_cb.adapter_properties_cb = getprop_success_cb,
- .expected_cb_count = 1,
+ .expected_hal_cb.adapter_properties_cb = check_count_properties_cb,
+ .expected_properties_num = 1,
+ .expected_properties = setprop_scanmode_none_props,
.expected_adapter_status = BT_STATUS_DONE,
- .expected_property.type = BT_PROPERTY_ADAPTER_SCAN_MODE,
- .expected_property.val = &setprop_scanmode_none,
- .expected_property.len = sizeof(setprop_scanmode_none),
};
static const struct generic_data bluetooth_discovery_start_success_test = {
@@ -1073,6 +1327,9 @@ static void teardown(const void *test_data)
data->if_bluetooth = NULL;
}
+ if (data->expected_properties_list)
+ g_slist_free(data->expected_properties_list);
+
data->device->close(data->device);
if (data->bluetoothd_pid)
@@ -1091,8 +1348,12 @@ static void test_enable(const void *test_data)
struct test_data *data = tester_get_data();
bt_status_t adapter_status;
+ uint8_t *bdaddr = (uint8_t *)hciemu_get_master_bdaddr(data->hciemu);
+
init_test_conditions(data);
+ bdaddr2android((const bdaddr_t *)bdaddr, &enable_done_bdaddr_val.address);
+
adapter_status = data->if_bluetooth->enable();
check_expected_status(adapter_status);
}
@@ -1102,8 +1363,12 @@ static void test_enable_done(const void *test_data)
struct test_data *data = tester_get_data();
bt_status_t adapter_status;
+ uint8_t *bdaddr = (uint8_t *)hciemu_get_master_bdaddr(data->hciemu);
+
init_test_conditions(data);
+ bdaddr2android((const bdaddr_t *)bdaddr, &enable_done_bdaddr_val.address);
+
adapter_status = data->if_bluetooth->enable();
check_expected_status(adapter_status);
}
@@ -1122,22 +1387,19 @@ static void test_disable(const void *test_data)
static void test_setprop_bdname_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_bdname_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
adapter_status = data->if_bluetooth->set_adapter_property(prop);
-
check_expected_status(adapter_status);
}
static void test_setprop_scanmode_succes(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_scanmode_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1149,8 +1411,7 @@ static void test_setprop_scanmode_succes(const void *test_data)
static void test_setprop_disctimeout_succes(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_disctimeout_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1162,12 +1423,14 @@ static void test_setprop_disctimeout_succes(const void *test_data)
static void test_getprop_bdaddr_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = setprop_bdaddr_props[0].prop;
bt_status_t adapter_status;
+ uint8_t *bdaddr = (uint8_t *)hciemu_get_master_bdaddr(data->hciemu);
init_test_conditions(data);
+ bdaddr2android((const bdaddr_t *)bdaddr, &test_getprop_bdaddr_val.address);
+
adapter_status = data->if_bluetooth->get_adapter_property(prop.type);
check_expected_status(adapter_status);
}
@@ -1175,8 +1438,7 @@ static void test_getprop_bdaddr_success(const void *test_data)
static void test_getprop_bdname_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(getprop_bdname_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1187,12 +1449,10 @@ static void test_getprop_bdname_success(const void *test_data)
adapter_status = data->if_bluetooth->get_adapter_property((*prop).type);
check_expected_status(adapter_status);
}
-
static void test_setprop_uuid_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_uuid_prop[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1204,8 +1464,7 @@ static void test_setprop_uuid_invalid(const void *test_data)
static void test_setprop_cod_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_cod_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1230,8 +1489,7 @@ static void test_setprop_tod_invalid(const void *test_data)
static void test_setprop_rssi_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_remote_rssi_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1243,8 +1501,7 @@ static void test_setprop_rssi_invalid(const void *test_data)
static void test_setprop_service_record_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_service_record_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1256,8 +1513,7 @@ static void test_setprop_service_record_invalid(const void *test_data)
static void test_setprop_bdaddr_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_bdaddr_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1269,8 +1525,8 @@ static void test_setprop_bdaddr_invalid(const void *test_data)
static void test_setprop_scanmode_connectable_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop =
+ &(setprop_scanmode_connectable_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1282,8 +1538,7 @@ static void test_setprop_scanmode_connectable_success(const void *test_data)
static void test_setprop_bonded_devices_invalid(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_bonded_devices_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1295,8 +1550,7 @@ static void test_setprop_bonded_devices_invalid(const void *test_data)
static void test_getprop_cod_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = setprop_cod_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1308,8 +1562,7 @@ static void test_getprop_cod_success(const void *test_data)
static void test_getprop_tod_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = setprop_tod_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1321,8 +1574,7 @@ static void test_getprop_tod_success(const void *test_data)
static void test_getprop_scanmode_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = setprop_scanmode_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1334,8 +1586,7 @@ static void test_getprop_scanmode_success(const void *test_data)
static void test_getprop_disctimeout_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = setprop_disctimeout_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1347,8 +1598,7 @@ static void test_getprop_disctimeout_success(const void *test_data)
static void test_getprop_uuids_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = getprop_uuids_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1360,8 +1610,7 @@ static void test_getprop_uuids_success(const void *test_data)
static void test_getprop_bondeddev_success(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t prop = test->expected_property;
+ const bt_property_t prop = getprop_bondeddev_props[0].prop;
bt_status_t adapter_status;
init_test_conditions(data);
@@ -1373,8 +1622,7 @@ static void test_getprop_bondeddev_success(const void *test_data)
static void test_setprop_scanmode_none_done(const void *test_data)
{
struct test_data *data = tester_get_data();
- const struct generic_data *test = data->test_data;
- const bt_property_t *prop = &test->expected_property;
+ const bt_property_t *prop = &(setprop_scanmode_none_props[0].prop);
bt_status_t adapter_status;
init_test_conditions(data);
--
1.8.5.2
^ permalink raw reply related
* [PATCH_v7 4/4] android/pan: Remove connected PAN devices on profile unregister call
From: Ravi kumar Veeramally @ 2014-01-10 14:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389363109-6312-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/android/pan.c b/android/pan.c
index 9f99ed9..205da71 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -752,10 +752,20 @@ bool bt_pan_register(const bdaddr_t *addr)
return true;
}
+static void pan_device_disconnected(gpointer data, gpointer user_data)
+{
+ struct pan_device *dev = data;
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
void bt_pan_unregister(void)
{
DBG("");
+ g_slist_foreach(devices, pan_device_disconnected, NULL);
+ devices = NULL;
+
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v7 3/4] android/pan: Implement PAN enable HAL api at daemon side
From: Ravi kumar Veeramally @ 2014-01-10 14:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389363109-6312-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 21a46b4..9f99ed9 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -576,18 +576,40 @@ static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
uint8_t status;
+ int err;
+
+ DBG("");
+
+ if (local_role == cmd->local_role) {
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+ }
+
+ /* destroy existing server */
+ destroy_nap_device();
switch (cmd->local_role) {
- case HAL_PAN_ROLE_PANU:
case HAL_PAN_ROLE_NAP:
- DBG("Not Implemented");
- status = HAL_STATUS_FAILED;
break;
+ case HAL_PAN_ROLE_NONE:
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
default:
status = HAL_STATUS_UNSUPPORTED;
- break;
+ goto reply;
}
+ local_role = cmd->local_role;
+ err = register_nap_server();
+ if (err < 0) {
+ status = HAL_STATUS_FAILED;
+ destroy_nap_device();
+ goto reply;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, status);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v7 2/4] android/pan: Listen for incoming connections and accept in NAP role
From: Ravi kumar Veeramally @ 2014-01-10 14:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389363109-6312-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Listen for incoming connections and accept it. Create bnep interface
add it to bridge and notify control and connection state information
through HAL. Remove the device on disconnect request. If android
settings UI does not have bluetooth tethering enabled it immediately
sends disconnect signal.
---
android/pan.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 182 insertions(+), 3 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index bb009f3..21a46b4 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -65,12 +65,15 @@ struct pan_device {
uint8_t role;
GIOChannel *io;
struct bnep *session;
+ guint watch;
};
static struct {
uint32_t record_id;
+ GIOChannel *io;
} nap_dev = {
.record_id = 0,
+ .io = NULL,
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -83,13 +86,19 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
static void pan_device_free(struct pan_device *dev)
{
+ if (dev->watch > 0) {
+ bnep_server_delete(BNEP_BRIDGE, dev->iface, &dev->dst);
+ g_source_remove(dev->watch);
+ }
+
if (dev->io) {
g_io_channel_shutdown(dev->io, FALSE, NULL);
g_io_channel_unref(dev->io);
- dev->io = NULL;
}
- bnep_free(dev->session);
+ if (dev->session)
+ bnep_free(dev->session);
+
devices = g_slist_remove(devices, dev);
g_free(dev);
@@ -300,7 +309,7 @@ static void bt_pan_disconnect(const void *buf, uint16_t len)
dev = l->data;
- if (dev->conn_state == HAL_PAN_STATE_CONNECTED)
+ if (dev->conn_state == HAL_PAN_STATE_CONNECTED && dev->session)
bnep_disconnect(dev->session);
bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
@@ -310,6 +319,154 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("disconnected");
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+ uint8_t packet[BNEP_MTU];
+ struct bnep_setup_conn_req *req = (void *) packet;
+ uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+ int sk, n;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Hangup or error or inval on BNEP socket");
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+ n = read(sk, packet, sizeof(packet));
+ if (n < 0) {
+ error("read(): %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
+ if (req->type == BNEP_CONTROL &&
+ req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+ error("cmd not understood");
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
+ req->ctrl);
+ goto failed;
+ }
+
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
+ error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
+ req->ctrl);
+ goto failed;
+ }
+
+ rsp = bnep_setup_decode(req, &dst_role, &src_role);
+ if (rsp) {
+ error("bnep_setup_decode failed");
+ goto failed;
+ }
+
+ rsp = bnep_setup_chk(dst_role, src_role);
+ if (rsp) {
+ error("benp_setup_chk failed");
+ goto failed;
+ }
+
+ if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
+ &dev->dst) < 0) {
+ error("server_connadd failed");
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto failed;
+ }
+
+ rsp = BNEP_SUCCESS;
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+
+ dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_watchdog_cb, dev);
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+
+ bt_pan_notify_ctrl_state(dev, HAL_PAN_CTRL_ENABLED);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTED);
+
+ return FALSE;
+
+failed:
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+ pan_device_free(dev);
+
+ return FALSE;
+}
+
+static void nap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ dev->watch = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_setup_cb, dev);
+}
+
+static void nap_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ struct pan_device *dev = NULL;
+ bdaddr_t dst;
+ char address[18];
+ GError *err = NULL;
+
+ DBG("");
+
+ bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ DBG("incoming connect request from %s", address);
+ dev = g_new0(struct pan_device, 1);
+ bacpy(&dev->dst, &dst);
+ local_role = HAL_PAN_ROLE_NAP;
+ dev->role = HAL_PAN_ROLE_PANU;
+
+ dev->io = g_io_channel_ref(chan);
+ g_io_channel_set_close_on_unref(dev->io, TRUE);
+
+ if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ devices = g_slist_append(devices, dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING);
+
+ return;
+
+failed:
+ g_free(dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
static int set_forward_delay(void)
{
int fd, ret;
@@ -378,10 +535,17 @@ static void destroy_nap_device(void)
DBG("");
nap_remove_bridge();
+
+ if (nap_dev.io) {
+ g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
+ g_io_channel_unref(nap_dev.io);
+ nap_dev.io = NULL;
+ }
}
static int register_nap_server(void)
{
+ GError *gerr;
int err;
DBG("");
@@ -390,6 +554,21 @@ static int register_nap_server(void)
if (err < 0)
return err;
+ nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_PSM, BNEP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_OMTU, BNEP_MTU,
+ BT_IO_OPT_IMTU, BNEP_MTU,
+ BT_IO_OPT_INVALID);
+
+ if (!nap_dev.io) {
+ destroy_nap_device();
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return -EINVAL;
+ }
+
return 0;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v7 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-10 14:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389363109-6312-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Register NAP server and adds bnep bridge. Removes bridge
on destroy call. Bridge mechanism is needed when device acting
as a server and listen for incoming connections.
---
android/pan.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 109 insertions(+), 5 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 38e353d..bb009f3 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -28,6 +28,11 @@
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
#include "btio/btio.h"
#include "lib/bluetooth.h"
@@ -45,11 +50,13 @@
#include "bluetooth.h"
#define SVC_HINT_NETWORKING 0x02
+#define BNEP_BRIDGE "bnep"
+#define FORWARD_DELAY_PATH "/sys/class/net/%s/bridge/forward_delay"
+#define DELAY_PATH_MAX 41
static bdaddr_t adapter_addr;
GSList *devices = NULL;
uint8_t local_role = HAL_PAN_ROLE_NONE;
-static uint32_t record_id = 0;
struct pan_device {
char iface[16];
@@ -60,6 +67,12 @@ struct pan_device {
struct bnep *session;
};
+static struct {
+ uint32_t record_id;
+} nap_dev = {
+ .record_id = 0,
+};
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct pan_device *dev = s;
@@ -297,6 +310,89 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static int set_forward_delay(void)
+{
+ int fd, ret;
+ char path[DELAY_PATH_MAX];
+
+ snprintf(path, sizeof(path), FORWARD_DELAY_PATH, BNEP_BRIDGE);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ ret = write(fd, "0", sizeof("0"));
+ close(fd);
+
+ return ret;
+}
+
+static int nap_create_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) < 0) {
+ err = -errno;
+ if (err != -EEXIST) {
+ close(sk);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ err = set_forward_delay();
+ if (err < 0)
+ ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+ close(sk);
+
+ return err;
+}
+
+static int nap_remove_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ close(sk);
+
+ if (err < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static void destroy_nap_device(void)
+{
+ DBG("");
+
+ nap_remove_bridge();
+}
+
+static int register_nap_server(void)
+{
+ int err;
+
+ DBG("");
+
+ err = nap_create_bridge();
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
@@ -437,11 +533,18 @@ bool bt_pan_register(const bdaddr_t *addr)
err = bnep_init();
if (err) {
error("bnep init failed");
- sdp_record_free(rec);
+ bt_adapter_remove_record(rec->handle);
+ return false;
+ }
+
+ err = register_nap_server();
+ if (err < 0) {
+ bt_adapter_remove_record(rec->handle);
+ bnep_cleanup();
return false;
}
- record_id = rec->handle;
+ nap_dev.record_id = rec->handle;
ipc_register(HAL_SERVICE_ID_PAN, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -455,6 +558,7 @@ void bt_pan_unregister(void)
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
- bt_adapter_remove_record(record_id);
- record_id = 0;
+ bt_adapter_remove_record(nap_dev.record_id);
+ nap_dev.record_id = 0;
+ destroy_nap_device();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v7 0/4] Add support for NAP role
From: Ravi kumar Veeramally @ 2014-01-10 14:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
v7: Rebase issue with _v6.
v6: Fixed Szymon's comments (use snprintf and defines).
v5: Fixed Szymon's comments and added his fix (crash when bridge create
fails).
v4: Fixed Szymon's and Luiz's comments.
v3: Fixed Johan's comments (removed fopen, fprintf and used open and write).
v2: Fixed Johan's comments.
v1: This patch set add support for NAP role. It register NAP server and create
bnep bridge and listen for incoming connections from client devices.
On incoming connection request it accepts connection, creates bnep interface
and notifies control state and connection state infromation. Removes device
on disconnect request. Android related changes are required to enable this
role. Patches sent to respective ML.
Ravi kumar Veeramally (4):
android/pan: Register Network Access Point
android/pan: Listen for incoming connections and accept in NAP role
android/pan: Implement PAN enable HAL api at daemon side
android/pan: Remove connected PAN devices on profile unregister call
android/pan.c | 339 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 327 insertions(+), 12 deletions(-)
--
1.8.3.2
^ permalink raw reply
* [PATCH_v6 4/4] android/pan: Remove connected PAN devices on profile unregister call
From: Ravi kumar Veeramally @ 2014-01-10 13:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389361840-5021-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/android/pan.c b/android/pan.c
index a733d22..8ea07a4 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -750,10 +750,20 @@ bool bt_pan_register(const bdaddr_t *addr)
return true;
}
+static void pan_device_disconnected(gpointer data, gpointer user_data)
+{
+ struct pan_device *dev = data;
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
void bt_pan_unregister(void)
{
DBG("");
+ g_slist_foreach(devices, pan_device_disconnected, NULL);
+ devices = NULL;
+
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v6 3/4] android/pan: Implement PAN enable HAL api at daemon side
From: Ravi kumar Veeramally @ 2014-01-10 13:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389361840-5021-1-git-send-email-ravikumar.veeramally@linux.intel.com>
---
android/pan.c | 30 ++++++++++++++++++++++++++----
1 file changed, 26 insertions(+), 4 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index d683945..a733d22 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -574,18 +574,40 @@ static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
uint8_t status;
+ int err;
+
+ DBG("");
+
+ if (local_role == cmd->local_role) {
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
+ }
+
+ /* destroy existing server */
+ destroy_nap_device();
switch (cmd->local_role) {
- case HAL_PAN_ROLE_PANU:
case HAL_PAN_ROLE_NAP:
- DBG("Not Implemented");
- status = HAL_STATUS_FAILED;
break;
+ case HAL_PAN_ROLE_NONE:
+ status = HAL_STATUS_SUCCESS;
+ goto reply;
default:
status = HAL_STATUS_UNSUPPORTED;
- break;
+ goto reply;
}
+ local_role = cmd->local_role;
+ err = register_nap_server();
+ if (err < 0) {
+ status = HAL_STATUS_FAILED;
+ destroy_nap_device();
+ goto reply;
+ }
+
+ status = HAL_STATUS_SUCCESS;
+
+reply:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, status);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v6 2/4] android/pan: Listen for incoming connections and accept in NAP role
From: Ravi kumar Veeramally @ 2014-01-10 13:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389361840-5021-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Listen for incoming connections and accept it. Create bnep interface
add it to bridge and notify control and connection state information
through HAL. Remove the device on disconnect request. If android
settings UI does not have bluetooth tethering enabled it immediately
sends disconnect signal.
---
android/pan.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 182 insertions(+), 3 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index ea0e34e..d683945 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -63,12 +63,15 @@ struct pan_device {
uint8_t role;
GIOChannel *io;
struct bnep *session;
+ guint watch;
};
static struct {
uint32_t record_id;
+ GIOChannel *io;
} nap_dev = {
.record_id = 0,
+ .io = NULL,
};
static int device_cmp(gconstpointer s, gconstpointer user_data)
@@ -81,13 +84,19 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
static void pan_device_free(struct pan_device *dev)
{
+ if (dev->watch > 0) {
+ bnep_server_delete(BNEP_BRIDGE, dev->iface, &dev->dst);
+ g_source_remove(dev->watch);
+ }
+
if (dev->io) {
g_io_channel_shutdown(dev->io, FALSE, NULL);
g_io_channel_unref(dev->io);
- dev->io = NULL;
}
- bnep_free(dev->session);
+ if (dev->session)
+ bnep_free(dev->session);
+
devices = g_slist_remove(devices, dev);
g_free(dev);
@@ -298,7 +307,7 @@ static void bt_pan_disconnect(const void *buf, uint16_t len)
dev = l->data;
- if (dev->conn_state == HAL_PAN_STATE_CONNECTED)
+ if (dev->conn_state == HAL_PAN_STATE_CONNECTED && dev->session)
bnep_disconnect(dev->session);
bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
@@ -308,6 +317,154 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static gboolean nap_watchdog_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("disconnected");
+
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+
+ return FALSE;
+}
+static gboolean nap_setup_cb(GIOChannel *chan, GIOCondition cond,
+ gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+ uint8_t packet[BNEP_MTU];
+ struct bnep_setup_conn_req *req = (void *) packet;
+ uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED;
+ int sk, n;
+
+ if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) {
+ error("Hangup or error or inval on BNEP socket");
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */
+ n = read(sk, packet, sizeof(packet));
+ if (n < 0) {
+ error("read(): %s(%d)", strerror(errno), errno);
+ goto failed;
+ }
+
+ /* Highest known control command id BNEP_FILTER_MULT_ADDR_RSP 0x06 */
+ if (req->type == BNEP_CONTROL &&
+ req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
+ error("cmd not understood");
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_CMD_NOT_UNDERSTOOD,
+ req->ctrl);
+ goto failed;
+ }
+
+ if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) {
+ error("cmd is not BNEP_SETUP_CONN_REQ %02X %02X", req->type,
+ req->ctrl);
+ goto failed;
+ }
+
+ rsp = bnep_setup_decode(req, &dst_role, &src_role);
+ if (rsp) {
+ error("bnep_setup_decode failed");
+ goto failed;
+ }
+
+ rsp = bnep_setup_chk(dst_role, src_role);
+ if (rsp) {
+ error("benp_setup_chk failed");
+ goto failed;
+ }
+
+ if (bnep_server_add(sk, dst_role, BNEP_BRIDGE, dev->iface,
+ &dev->dst) < 0) {
+ error("server_connadd failed");
+ rsp = BNEP_CONN_NOT_ALLOWED;
+ goto failed;
+ }
+
+ rsp = BNEP_SUCCESS;
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+
+ dev->watch = g_io_add_watch(chan, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_watchdog_cb, dev);
+ g_io_channel_unref(dev->io);
+ dev->io = NULL;
+
+ bt_pan_notify_ctrl_state(dev, HAL_PAN_CTRL_ENABLED);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTED);
+
+ return FALSE;
+
+failed:
+ bnep_send_ctrl_rsp(sk, BNEP_CONTROL, BNEP_SETUP_CONN_RSP, rsp);
+ pan_device_free(dev);
+
+ return FALSE;
+}
+
+static void nap_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+ struct pan_device *dev = user_data;
+
+ DBG("");
+
+ if (err) {
+ error("%s", err->message);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+ return;
+ }
+
+ g_io_channel_set_close_on_unref(chan, TRUE);
+ dev->watch = g_io_add_watch(chan,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ nap_setup_cb, dev);
+}
+
+static void nap_confirm_cb(GIOChannel *chan, gpointer data)
+{
+ struct pan_device *dev = NULL;
+ bdaddr_t dst;
+ char address[18];
+ GError *err = NULL;
+
+ DBG("");
+
+ bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+ if (err) {
+ error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ DBG("incoming connect request from %s", address);
+ dev = g_new0(struct pan_device, 1);
+ bacpy(&dev->dst, &dst);
+ local_role = HAL_PAN_ROLE_NAP;
+ dev->role = HAL_PAN_ROLE_PANU;
+
+ dev->io = g_io_channel_ref(chan);
+ g_io_channel_set_close_on_unref(dev->io, TRUE);
+
+ if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) {
+ error("bt_io_accept: %s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ devices = g_slist_append(devices, dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING);
+
+ return;
+
+failed:
+ g_free(dev);
+ bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED);
+}
+
static int set_forward_delay(void)
{
int fd, ret;
@@ -376,10 +533,17 @@ static void destroy_nap_device(void)
DBG("");
nap_remove_bridge();
+
+ if (nap_dev.io) {
+ g_io_channel_shutdown(nap_dev.io, FALSE, NULL);
+ g_io_channel_unref(nap_dev.io);
+ nap_dev.io = NULL;
+ }
}
static int register_nap_server(void)
{
+ GError *gerr;
int err;
DBG("");
@@ -388,6 +552,21 @@ static int register_nap_server(void)
if (err < 0)
return err;
+ nap_dev.io = bt_io_listen(NULL, nap_confirm_cb, NULL, NULL, &gerr,
+ BT_IO_OPT_SOURCE_BDADDR, &adapter_addr,
+ BT_IO_OPT_PSM, BNEP_PSM,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_OMTU, BNEP_MTU,
+ BT_IO_OPT_IMTU, BNEP_MTU,
+ BT_IO_OPT_INVALID);
+
+ if (!nap_dev.io) {
+ destroy_nap_device();
+ error("%s", gerr->message);
+ g_error_free(gerr);
+ return -EINVAL;
+ }
+
return 0;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v6 1/4] android/pan: Register Network Access Point
From: Ravi kumar Veeramally @ 2014-01-10 13:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1389361840-5021-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Register NAP server and adds bnep bridge. Removes bridge
on destroy call. Bridge mechanism is needed when device acting
as a server and listen for incoming connections.
---
android/pan.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 107 insertions(+), 5 deletions(-)
diff --git a/android/pan.c b/android/pan.c
index 38e353d..ea0e34e 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -28,6 +28,11 @@
#include <unistd.h>
#include <fcntl.h>
#include <glib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <linux/sockios.h>
#include "btio/btio.h"
#include "lib/bluetooth.h"
@@ -45,11 +50,11 @@
#include "bluetooth.h"
#define SVC_HINT_NETWORKING 0x02
+#define BNEP_BRIDGE "bnep"
static bdaddr_t adapter_addr;
GSList *devices = NULL;
uint8_t local_role = HAL_PAN_ROLE_NONE;
-static uint32_t record_id = 0;
struct pan_device {
char iface[16];
@@ -60,6 +65,12 @@ struct pan_device {
struct bnep *session;
};
+static struct {
+ uint32_t record_id;
+} nap_dev = {
+ .record_id = 0,
+};
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct pan_device *dev = s;
@@ -297,6 +308,89 @@ failed:
ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_DISCONNECT, status);
}
+static int set_forward_delay(void)
+{
+ int fd, ret;
+ char path[41];
+
+ sprintf(path, "/sys/class/net/%s/bridge/forward_delay", BNEP_BRIDGE);
+
+ fd = open(path, O_RDWR);
+ if (fd < 0)
+ return -errno;
+
+ ret = write(fd, "0", sizeof("0"));
+ close(fd);
+
+ return ret;
+}
+
+static int nap_create_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ if (ioctl(sk, SIOCBRADDBR, BNEP_BRIDGE) < 0) {
+ err = -errno;
+ if (err != -EEXIST) {
+ close(sk);
+ return -EOPNOTSUPP;
+ }
+ }
+
+ err = set_forward_delay();
+ if (err < 0)
+ ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+
+ close(sk);
+
+ return err;
+}
+
+static int nap_remove_bridge(void)
+{
+ int sk, err;
+
+ DBG("%s", BNEP_BRIDGE);
+
+ sk = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (sk < 0)
+ return -EOPNOTSUPP;
+
+ err = ioctl(sk, SIOCBRDELBR, BNEP_BRIDGE);
+ close(sk);
+
+ if (err < 0)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static void destroy_nap_device(void)
+{
+ DBG("");
+
+ nap_remove_bridge();
+}
+
+static int register_nap_server(void)
+{
+ int err;
+
+ DBG("");
+
+ err = nap_create_bridge();
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
static void bt_pan_enable(const void *buf, uint16_t len)
{
const struct hal_cmd_pan_enable *cmd = buf;
@@ -437,11 +531,18 @@ bool bt_pan_register(const bdaddr_t *addr)
err = bnep_init();
if (err) {
error("bnep init failed");
- sdp_record_free(rec);
+ bt_adapter_remove_record(rec->handle);
+ return false;
+ }
+
+ err = register_nap_server();
+ if (err < 0) {
+ bt_adapter_remove_record(rec->handle);
+ bnep_cleanup();
return false;
}
- record_id = rec->handle;
+ nap_dev.record_id = rec->handle;
ipc_register(HAL_SERVICE_ID_PAN, cmd_handlers,
G_N_ELEMENTS(cmd_handlers));
@@ -455,6 +556,7 @@ void bt_pan_unregister(void)
bnep_cleanup();
ipc_unregister(HAL_SERVICE_ID_PAN);
- bt_adapter_remove_record(record_id);
- record_id = 0;
+ bt_adapter_remove_record(nap_dev.record_id);
+ nap_dev.record_id = 0;
+ destroy_nap_device();
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH_v6 0/4] Add support for NAP role
From: Ravi kumar Veeramally @ 2014-01-10 13:50 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
v6: Fixed Szymon's comments (use snprintf and defines).
v5: Fixed Szymon's comments and added his fix (crash when bridge create
fails).
v4: Fixed Szymon's and Luiz's comments.
v3: Fixed Johan's comments (removed fopen, fprintf and used open and write).
v2: Fixed Johan's comments.
v1: This patch set add support for NAP role. It register NAP server and create
bnep bridge and listen for incoming connections from client devices.
On incoming connection request it accepts connection, creates bnep interface
and notifies control state and connection state infromation. Removes device
on disconnect request. Android related changes are required to enable this
role. Patches sent to respective ML.
Ravi kumar Veeramally (4):
android/pan: Register Network Access Point
android/pan: Listen for incoming connections and accept in NAP role
android/pan: Implement PAN enable HAL api at daemon side
android/pan: Remove connected PAN devices on profile unregister call
android/pan.c | 337 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 325 insertions(+), 12 deletions(-)
--
1.8.3.2
^ permalink raw reply
* Re: [PATCH v4] Bluetooth: Add hci_h4p driver
From: Sebastian Reichel @ 2014-01-10 13:44 UTC (permalink / raw)
To: Pavel Machek
Cc: Marcel Holtmann, Pali Rohár,
Ивайло Димитров,
Gustavo F. Padovan, Johan Hedberg, linux-kernel,
linux-bluetooth@vger.kernel.org development, Ville Tervo
In-Reply-To: <20140110121805.GA21117@amd.pavel.ucw.cz>
[-- Attachment #1: Type: text/plain, Size: 6143 bytes --]
Hi Pavel,
You have missed some things. See inline comments below.
On Fri, Jan 10, 2014 at 01:18:05PM +0100, Pavel Machek wrote:
> diff --git a/drivers/bluetooth/nokia_core.c b/drivers/bluetooth/nokia_core.c
> index 5c7acad..d6b0701 100644
> --- a/drivers/bluetooth/nokia_core.c
> v+++ b/drivers/bluetooth/nokia_core.c
> @@ -39,6 +39,7 @@
> #include <linux/gpio.h>
> #include <linux/timer.h>
> #include <linux/kthread.h>
> +#include <linux/io.h>
>
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> @@ -1079,7 +1080,7 @@ static int hci_h4p_probe(struct platform_device *pdev)
> int err;
>
> dev_info(&pdev->dev, "Registering HCI H4P device\n");
> - info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
> + info = devm_kzalloc(&pdev->dev, sizeof(struct hci_h4p_info), GFP_KERNEL);
> if (!info)
> return -ENOMEM;
>
> @@ -1092,7 +1093,6 @@ static int hci_h4p_probe(struct platform_device *pdev)
>
> if (pdev->dev.platform_data == NULL) {
> dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
> - kfree(info);
> return -ENODATA;
> }
>
> @@ -1113,67 +1113,59 @@ static int hci_h4p_probe(struct platform_device *pdev)
> complete_all(&info->test_completion);
>
> if (!info->reset_gpio_shared) {
> - err = gpio_request(info->reset_gpio, "bt_reset");
> + err = devm_gpio_request_one(&pdev->dev, info->reset_gpio,
> + GPIOF_OUT_INIT_LOW, "bt_reset");
> if (err < 0) {
> dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
> info->reset_gpio);
> - goto cleanup_setup;
> + return err;
> }
> }
>
> - err = gpio_request(info->bt_wakeup_gpio, "bt_wakeup");
> + err = devm_gpio_request_one(&pdev->dev, info->bt_wakeup_gpio,
> + GPIOF_OUT_INIT_LOW, "bt_wakeup");
> +
> if (err < 0) {
> dev_err(info->dev, "Cannot get GPIO line 0x%d",
> info->bt_wakeup_gpio);
> - if (!info->reset_gpio_shared)
> - gpio_free(info->reset_gpio);
> - goto cleanup_setup;
> + return err;
> }
>
> - err = gpio_request(info->host_wakeup_gpio, "host_wakeup");
> + err = devm_gpio_request_one(&pdev->dev, info->host_wakeup_gpio,
> + GPIOF_DIR_IN, "host_wakeup");
> if (err < 0) {
> dev_err(info->dev, "Cannot get GPIO line %d",
> info->host_wakeup_gpio);
> - if (!info->reset_gpio_shared)
> - gpio_free(info->reset_gpio);
> - gpio_free(info->bt_wakeup_gpio);
> - goto cleanup_setup;
> + return err;
> }
>
> - gpio_direction_output(info->reset_gpio, 0);
> - gpio_direction_output(info->bt_wakeup_gpio, 0);
> - gpio_direction_input(info->host_wakeup_gpio);
> -
> info->irq = bt_plat_data->uart_irq;
> - info->uart_base = ioremap(bt_plat_data->uart_base, SZ_2K);
> - info->uart_iclk = clk_get(NULL, bt_plat_data->uart_iclk);
> - info->uart_fclk = clk_get(NULL, bt_plat_data->uart_fclk);
> + info->uart_base = devm_ioremap(&pdev->dev, bt_plat_data->uart_base, SZ_2K);
> + info->uart_iclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_iclk);
> + info->uart_fclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_fclk);
>
> err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED, "hci_h4p",
> info);
This one should also use devm_request_irq(). Especially since you
removed the cleanup in the probe function already ;)
> if (err < 0) {
> dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
> - goto cleanup;
> + return err;
> }
>
> - err = request_irq(gpio_to_irq(info->host_wakeup_gpio),
> + err = devm_request_irq(&pdev->dev, gpio_to_irq(info->host_wakeup_gpio),
> hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING |
> IRQF_TRIGGER_RISING | IRQF_DISABLED,
> "hci_h4p_wkup", info);
> if (err < 0) {
> dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
> gpio_to_irq(info->host_wakeup_gpio));
> - free_irq(info->irq, info);
> - goto cleanup;
> + return err;
> }
>
> err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
> if (err < 0) {
> dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
> gpio_to_irq(info->host_wakeup_gpio));
> - free_irq(info->irq, info);
> - free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
> - goto cleanup;
> + return err;
> }
>
> init_timer_deferrable(&info->lazy_release);
> @@ -1182,7 +1174,7 @@ static int hci_h4p_probe(struct platform_device *pdev)
> hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
> err = hci_h4p_reset_uart(info);
> if (err < 0)
> - goto cleanup_irq;
> + return err;
> gpio_set_value(info->reset_gpio, 0);
> hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
>
> @@ -1190,23 +1182,10 @@ static int hci_h4p_probe(struct platform_device *pdev)
>
> if (hci_h4p_register_hdev(info) < 0) {
> dev_err(info->dev, "failed to register hci_h4p hci device\n");
> - goto cleanup_irq;
> + return -EINVAL;
> }
>
> return 0;
> -
> -cleanup_irq:
> - free_irq(info->irq, (void *)info);
> - free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
> -cleanup:
> - gpio_set_value(info->reset_gpio, 0);
> - if (!info->reset_gpio_shared)
> - gpio_free(info->reset_gpio);
> - gpio_free(info->bt_wakeup_gpio);
> - gpio_free(info->host_wakeup_gpio);
> -cleanup_setup:
> - kfree(info);
> - return err;
> }
>
> static int hci_h4p_remove(struct platform_device *pdev)
> @@ -1217,15 +1196,11 @@ static int hci_h4p_remove(struct platform_device *pdev)
>
> hci_h4p_sysfs_remove_files(info->dev);
> hci_h4p_hci_close(info->hdev);
> - free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
> hci_unregister_dev(info->hdev);
> hci_free_dev(info->hdev);
> - if (!info->reset_gpio_shared)
> - gpio_free(info->reset_gpio);
> gpio_free(info->bt_wakeup_gpio);
> gpio_free(info->host_wakeup_gpio);
those two gpios are also managed. No need to free them manually.
> free_irq(info->irq, (void *) info);
Once this irq is also requested using managed resources you can also
drop this line.
> - kfree(info);
>
> return 0;
> }
> [...]
-- Sebastian
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]
^ permalink raw reply
* Re: [PATCH BlueZ 1/3] android: Convert libaudio-internal to a plugin
From: Luiz Augusto von Dentz @ 2014-01-10 13:39 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1389356048-4333-1-git-send-email-luiz.dentz@gmail.com>
Hi,
On Fri, Jan 10, 2014 at 2:14 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This convert the static library libaudio-internal.la to
> audio.a2dp.default.so when building with autotools.
> ---
> android/Makefile.am | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 0a32a95..97173db 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -114,18 +114,19 @@ android_android_tester_LDADD = lib/libbluetooth-internal.la \
>
> android_android_tester_LDFLAGS = -pthread
>
> -noinst_LTLIBRARIES += android/libaudio-internal.la
> +plugin_LTLIBRARIES += android/audio.a2dp.default.la
>
> -android_libaudio_internal_la_SOURCES = android/audio-msg.h \
> +android_audio_a2dp_default_la_SOURCES = android/audio-msg.h \
> android/hal-audio.c \
> android/hardware/audio.h \
> android/hardware/audio_effect.h \
> android/hardware/hardware.h \
> android/system/audio.h
>
> -android_libaudio_internal_la_CFLAGS = -I$(srcdir)/android
> +android_audio_a2dp_default_la_CFLAGS = -I$(srcdir)/android
>
> -android_libaudio_internal_la_LDFLAGS = -pthread
> +android_audio_a2dp_default_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
> + -no-undefined -pthread
>
> endif
>
> --
> 1.8.4.2
This now pushed.
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] android-tester: Add possibility to debug mgmt
From: Marcin Kraglak @ 2014-01-10 13:23 UTC (permalink / raw)
To: linux-bluetooth
Print mgmt debug info if debug flag is set in android-tester.
---
android/android-tester.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/android/android-tester.c b/android/android-tester.c
index 0185f99..ce1cedf 100644
--- a/android/android-tester.c
+++ b/android/android-tester.c
@@ -95,6 +95,13 @@ struct test_data {
static char exec_dir[PATH_MAX + 1];
+static void mgmt_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ tester_print("%s%s", prefix, str);
+}
+
static void test_update_state(void)
{
struct test_data *data = tester_get_data();
@@ -334,9 +341,6 @@ static void test_pre_setup(const void *test_data)
{
struct test_data *data = tester_get_data();
- if (!tester_use_debug())
- fclose(stderr);
-
data->mgmt = mgmt_new_default();
if (!data->mgmt) {
tester_warn("Failed to setup management interface");
@@ -344,6 +348,11 @@ static void test_pre_setup(const void *test_data)
return;
}
+ if (!tester_use_debug())
+ fclose(stderr);
+ else
+ mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0,
NULL, read_index_list_callback, NULL, NULL);
}
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH v4] Bluetooth: Add hci_h4p driver
From: Pavel Machek @ 2014-01-10 12:18 UTC (permalink / raw)
To: Marcel Holtmann, Pali Rohár,
Ивайло Димитров,
Gustavo F. Padovan, Johan Hedberg, linux-kernel,
linux-bluetooth@vger.kernel.org development, Ville Tervo
In-Reply-To: <20140110003231.GA14141@earth.universe>
On Fri 2014-01-10 01:32:31, Sebastian Reichel wrote:
> Hi Pavel,
>
> On Fri, Jan 10, 2014 at 12:38:43AM +0100, Pavel Machek wrote:
> > > Here are some cleanup suggestions for probe, removal & module
> > > initialization functions.
> >
> > ...and here's the patch implementing those suggestions. Thanks!
>
> That looks right, but you forgot to cleanup hci_h4p_remove. Also I
> suggest to simply merge this as v5.
Here it goes, now with hci_h4p_remove fixed. v5 will follow.
commit b77cc9dd6f6897183d97717cec63aaa248317f95
Author: Pavel <pavel@ucw.cz>
Date: Fri Jan 10 13:14:45 2014 +0100
Switch to devm_ functions to make code cleaner.
Reported-by: Sebastian Reichel <sre@ring0.de>
Signed-off-by: Pavel Machek <pavel@ucw.cz>
diff --git a/drivers/bluetooth/nokia_core.c b/drivers/bluetooth/nokia_core.c
index 5c7acad..d6b0701 100644
--- a/drivers/bluetooth/nokia_core.c
v+++ b/drivers/bluetooth/nokia_core.c
@@ -39,6 +39,7 @@
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/kthread.h>
+#include <linux/io.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -1079,7 +1080,7 @@ static int hci_h4p_probe(struct platform_device *pdev)
int err;
dev_info(&pdev->dev, "Registering HCI H4P device\n");
- info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct hci_h4p_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -1092,7 +1093,6 @@ static int hci_h4p_probe(struct platform_device *pdev)
if (pdev->dev.platform_data == NULL) {
dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
- kfree(info);
return -ENODATA;
}
@@ -1113,67 +1113,59 @@ static int hci_h4p_probe(struct platform_device *pdev)
complete_all(&info->test_completion);
if (!info->reset_gpio_shared) {
- err = gpio_request(info->reset_gpio, "bt_reset");
+ err = devm_gpio_request_one(&pdev->dev, info->reset_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_reset");
if (err < 0) {
dev_err(&pdev->dev, "Cannot get GPIO line %d\n",
info->reset_gpio);
- goto cleanup_setup;
+ return err;
}
}
- err = gpio_request(info->bt_wakeup_gpio, "bt_wakeup");
+ err = devm_gpio_request_one(&pdev->dev, info->bt_wakeup_gpio,
+ GPIOF_OUT_INIT_LOW, "bt_wakeup");
+
if (err < 0) {
dev_err(info->dev, "Cannot get GPIO line 0x%d",
info->bt_wakeup_gpio);
- if (!info->reset_gpio_shared)
- gpio_free(info->reset_gpio);
- goto cleanup_setup;
+ return err;
}
- err = gpio_request(info->host_wakeup_gpio, "host_wakeup");
+ err = devm_gpio_request_one(&pdev->dev, info->host_wakeup_gpio,
+ GPIOF_DIR_IN, "host_wakeup");
if (err < 0) {
dev_err(info->dev, "Cannot get GPIO line %d",
info->host_wakeup_gpio);
- if (!info->reset_gpio_shared)
- gpio_free(info->reset_gpio);
- gpio_free(info->bt_wakeup_gpio);
- goto cleanup_setup;
+ return err;
}
- gpio_direction_output(info->reset_gpio, 0);
- gpio_direction_output(info->bt_wakeup_gpio, 0);
- gpio_direction_input(info->host_wakeup_gpio);
-
info->irq = bt_plat_data->uart_irq;
- info->uart_base = ioremap(bt_plat_data->uart_base, SZ_2K);
- info->uart_iclk = clk_get(NULL, bt_plat_data->uart_iclk);
- info->uart_fclk = clk_get(NULL, bt_plat_data->uart_fclk);
+ info->uart_base = devm_ioremap(&pdev->dev, bt_plat_data->uart_base, SZ_2K);
+ info->uart_iclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_iclk);
+ info->uart_fclk = devm_clk_get(&pdev->dev, bt_plat_data->uart_fclk);
err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED, "hci_h4p",
info);
if (err < 0) {
dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
- goto cleanup;
+ return err;
}
- err = request_irq(gpio_to_irq(info->host_wakeup_gpio),
+ err = devm_request_irq(&pdev->dev, gpio_to_irq(info->host_wakeup_gpio),
hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING |
IRQF_TRIGGER_RISING | IRQF_DISABLED,
"hci_h4p_wkup", info);
if (err < 0) {
dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
gpio_to_irq(info->host_wakeup_gpio));
- free_irq(info->irq, info);
- goto cleanup;
+ return err;
}
err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
if (err < 0) {
dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
gpio_to_irq(info->host_wakeup_gpio));
- free_irq(info->irq, info);
- free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
- goto cleanup;
+ return err;
}
init_timer_deferrable(&info->lazy_release);
@@ -1182,7 +1174,7 @@ static int hci_h4p_probe(struct platform_device *pdev)
hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
err = hci_h4p_reset_uart(info);
if (err < 0)
- goto cleanup_irq;
+ return err;
gpio_set_value(info->reset_gpio, 0);
hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
@@ -1190,23 +1182,10 @@ static int hci_h4p_probe(struct platform_device *pdev)
if (hci_h4p_register_hdev(info) < 0) {
dev_err(info->dev, "failed to register hci_h4p hci device\n");
- goto cleanup_irq;
+ return -EINVAL;
}
return 0;
-
-cleanup_irq:
- free_irq(info->irq, (void *)info);
- free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
-cleanup:
- gpio_set_value(info->reset_gpio, 0);
- if (!info->reset_gpio_shared)
- gpio_free(info->reset_gpio);
- gpio_free(info->bt_wakeup_gpio);
- gpio_free(info->host_wakeup_gpio);
-cleanup_setup:
- kfree(info);
- return err;
}
static int hci_h4p_remove(struct platform_device *pdev)
@@ -1217,15 +1196,11 @@ static int hci_h4p_remove(struct platform_device *pdev)
hci_h4p_sysfs_remove_files(info->dev);
hci_h4p_hci_close(info->hdev);
- free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
hci_unregister_dev(info->hdev);
hci_free_dev(info->hdev);
- if (!info->reset_gpio_shared)
- gpio_free(info->reset_gpio);
gpio_free(info->bt_wakeup_gpio);
gpio_free(info->host_wakeup_gpio);
free_irq(info->irq, (void *) info);
- kfree(info);
return 0;
}
@@ -1238,25 +1213,7 @@ static struct platform_driver hci_h4p_driver = {
},
};
-static int __init hci_h4p_init(void)
-{
- int err = 0;
-
- /* Register the driver with LDM */
- err = platform_driver_register(&hci_h4p_driver);
- if (err < 0)
- printk(KERN_WARNING "failed to register hci_h4p driver\n");
-
- return err;
-}
-
-static void __exit hci_h4p_exit(void)
-{
- platform_driver_unregister(&hci_h4p_driver);
-}
-
-module_init(hci_h4p_init);
-module_exit(hci_h4p_exit);
+module_platform_driver(hci_h4p_driver);
MODULE_ALIAS("platform:hci_h4p");
MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH BlueZ 3/3] android: Load bluetooth.default.so as a module
From: Luiz Augusto von Dentz @ 2014-01-10 12:14 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389356048-4333-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This makes haltest and android-tester to load bluetooth.default.so
instead of linking directly to it.
---
android/Makefile.am | 26 +++++-----
android/hardware/hardware.c | 124 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 138 insertions(+), 12 deletions(-)
create mode 100644 android/hardware/hardware.c
diff --git a/android/Makefile.am b/android/Makefile.am
index 4b843b2..f5e8c99 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -1,4 +1,6 @@
if ANDROID
+android_plugindir = $(abs_top_srcdir)/android/.libs
+
noinst_PROGRAMS += android/system-emulator
android_system_emulator_SOURCES = android/system-emulator.c \
@@ -61,7 +63,8 @@ android_bluetooth_default_la_SOURCES = android/hal.h android/hal-bluetooth.c \
android/hardware/hardware.h \
android/cutils/properties.h \
android/hal-log.h \
- android/hal-ipc.h android/hal-ipc.c
+ android/hal-ipc.h android/hal-ipc.c \
+ android/hal-utils.h android/hal-utils.c
android_bluetooth_default_la_CPPFLAGS = -I$(srcdir)/android \
-DPLATFORM_SDK_VERSION=19
@@ -86,15 +89,14 @@ android_haltest_SOURCES = android/client/haltest.c \
android/client/if-hh.c \
android/client/if-pan.c \
android/client/if-sock.c \
- android/client/hwmodule.c \
+ android/hardware/hardware.c \
android/hal-utils.h android/hal-utils.c
-android_haltest_LDADD = android/bluetooth.default.la
-
android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
- -DPLATFORM_SDK_VERSION=19
+ -DPLATFORM_SDK_VERSION=19 \
+ -DPLUGINDIR=\""$(android_plugindir)"\"
-android_haltest_LDFLAGS = -pthread
+android_haltest_LDFLAGS = -pthread -ldl
noinst_PROGRAMS += android/android-tester
@@ -106,15 +108,15 @@ android_android_tester_SOURCES = emulator/btdev.h emulator/btdev.c \
src/shared/mgmt.h src/shared/mgmt.c \
src/shared/hciemu.h src/shared/hciemu.c \
src/shared/tester.h src/shared/tester.c \
- android/hal-utils.h android/hal-utils.c \
- android/client/hwmodule.c android/android-tester.c
+ android/hardware/hardware.c \
+ android/android-tester.c
-android_android_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android
+android_android_tester_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
+ -DPLUGINDIR=\""$(android_plugindir)"\"
-android_android_tester_LDADD = lib/libbluetooth-internal.la \
- android/bluetooth.default.la @GLIB_LIBS@
+android_android_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
-android_android_tester_LDFLAGS = -pthread
+android_android_tester_LDFLAGS = -pthread -ldl
plugin_LTLIBRARIES += android/audio.a2dp.default.la
diff --git a/android/hardware/hardware.c b/android/hardware/hardware.c
new file mode 100644
index 0000000..4bd5eba
--- /dev/null
+++ b/android/hardware/hardware.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hardware/hardware.h>
+
+#include <dlfcn.h>
+#include <string.h>
+#include <pthread.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#define LOG_TAG "HAL"
+
+#define LOG_INFO " I"
+#define LOG_WARN " W"
+#define LOG_ERROR " E"
+#define LOG_DEBUG " D"
+#define ALOG(pri, tag, fmt, arg...) fprintf(stderr, tag pri": " fmt"\n", ##arg)
+
+#define info(fmt, arg...) ALOG(LOG_INFO, LOG_TAG, fmt, ##arg)
+#define warn(fmt, arg...) ALOG(LOG_WARN, LOG_TAG, fmt, ##arg)
+#define error(fmt, arg...) ALOG(LOG_ERROR, LOG_TAG, fmt, ##arg)
+
+/**
+ * Load the file defined by the variant and if successful
+ * return the dlopen handle and the hmi.
+ * @return 0 = success, !0 = failure.
+ */
+static int load(const char *id,
+ const char *path,
+ const struct hw_module_t **pHmi)
+{
+ int status;
+ void *handle;
+ struct hw_module_t *hmi;
+ const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
+
+ /*
+ * load the symbols resolving undefined symbols before
+ * dlopen returns. Since RTLD_GLOBAL is not or'd in with
+ * RTLD_NOW the external symbols will not be global
+ */
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ char const *err_str = dlerror();
+ error("load: module=%s\n%s", path, err_str?err_str:"unknown");
+ status = -EINVAL;
+ goto done;
+ }
+
+ /* Get the address of the struct hal_module_info. */
+ hmi = (struct hw_module_t *)dlsym(handle, sym);
+ if (hmi == NULL) {
+ error("load: couldn't find symbol %s", sym);
+ status = -EINVAL;
+ goto done;
+ }
+
+ /* Check that the id matches */
+ if (strcmp(id, hmi->id) != 0) {
+ error("load: id=%s != hmi->id=%s", id, hmi->id);
+ status = -EINVAL;
+ goto done;
+ }
+
+ hmi->dso = handle;
+
+ *pHmi = hmi;
+
+ info("loaded HAL id=%s path=%s hmi=%p handle=%p",
+ id, path, *pHmi, handle);
+
+ return 0;
+
+done:
+ hmi = NULL;
+ if (handle != NULL) {
+ dlclose(handle);
+ handle = NULL;
+ }
+
+ return status;
+}
+
+int hw_get_module_by_class(const char *class_id, const char *inst,
+ const struct hw_module_t **module)
+{
+ char path[PATH_MAX];
+ char name[PATH_MAX];
+
+ if (inst)
+ snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
+ else
+ snprintf(name, PATH_MAX, "%s", class_id);
+
+ /*
+ * Here we rely on the fact that calling dlopen multiple times on
+ * the same .so will simply increment a refcount (and not load
+ * a new copy of the library).
+ * We also assume that dlopen() is thread-safe.
+ */
+ snprintf(path, sizeof(path), "%s/%s.default.so", PLUGINDIR, name);
+
+ return load(class_id, path, module);
+}
+
+int hw_get_module(const char *id, const struct hw_module_t **module)
+{
+ return hw_get_module_by_class(id, NULL, module);
+}
--
1.8.4.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox