Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH v5 BlueZ 0/4] Connection Update improvements
From: Felipe F. Tonello @ 2017-04-13 12:21 UTC (permalink / raw)
  To: linux-bluetooth
  Cc: linux-kernel, Marcel Holtmann, Johan Hedberg,
	Luiz Augusto von Dentz

These changes implements compliant Bluetooth support for any possible way to
update a connection parameter. Missing functionality is required to be
implemented in user-space, which this patchset allows it.

Changes from v4:
 * Handle Slave Connection Interval Range AD in kernel instead of
   user-space
 * Removed new MGMT command, it is unnecessary since it was only supposed
   to be used for the Slave Connection Interval Range support, which now
   has been implemented in the kernel.

Changes from v3:
 * Remove role check in refactored function
 * Added handler for Connection Parameter Update Response
 * Use Update Request when updating the connection parameters in slave
 * Fix MGMT command name to ADD instead of UPDATE

Changes from v2:
 * Added new MGMT command
 * Roll back to first socket option implementation, details are on the
   patch iself.

Changes from v1:
 * Use simpler user-space API
 * Added refactor function

Felipe F. Tonello (4):
  Bluetooth: L2CAP: Refactor L2CAP_CONN_PARAM_UPDATE_REQ into a function
  Bluetooth: L2CAP: Add handler for Connection Parameter Update Response
  Bluetooth: L2CAP: Add BT_LE_CONN_PARAM socket option
  Bluetooth: Handle Slave Connection Interval Range AD

 include/net/bluetooth/bluetooth.h |   8 +++
 include/net/bluetooth/l2cap.h     |   5 ++
 net/bluetooth/l2cap_core.c        |  78 +++++++++++++++++++++++----
 net/bluetooth/l2cap_sock.c        | 110 ++++++++++++++++++++++++++++++++++++++
 net/bluetooth/mgmt.c              |  53 ++++++++++++++++++
 5 files changed, 243 insertions(+), 11 deletions(-)

-- 
2.12.2

^ permalink raw reply

* GATT Server: DBus GATT Services not advertised/exported
From: Olivier MARTIN @ 2017-04-13 11:14 UTC (permalink / raw)
  To: linux-bluetooth

Hi all,
I am having issue to advertise/export GATT services exposed through DBus 
API. I tried `./test/example-gatt-server`. And I also tried to merge 
`./test/example-advertisement` into `./test/example-gatt-server`. But in 
both cases I only see the two compulsory GATT services:
- Generic Access Service (0x1800)
- Generic Attribute Service (0x1801)

I am using Bluez v5.44. And I also tried Bluez v5.37.

GATT Services seem to be discovered by Bluez (note: I added additional 
debug statement all prefixed with '#'):

bluetoothd[16877]: src/gatt-database.c:manager_register_app() # 
manager_register_app
bluetoothd[16877]: src/gatt-database.c:create_app() # create_app
bluetoothd[16877]: src/gatt-database.c:manager_register_app() 
Registering application: :1.404:/
bluetoothd[16877]: src/advertising.c:register_advertisement() 
RegisterAdvertisement
bluetoothd[16877]: src/advertising.c:client_create() Adding proxy for 
/org/bluez/example/advertisement0
bluetoothd[16877]: src/advertising.c:register_advertisement() Registered 
advertisement at path /org/bluez/example/advertisement0
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service0/char2, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char0/desc0, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char2/desc3, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char2, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service1/char0, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char1, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service0/char1, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char1/desc3, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char1/desc2, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service0/char0, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2, iface: org.bluez.GattService1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service1, iface: org.bluez.GattService1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service0, iface: org.bluez.GattService1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char0/desc1, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char2/desc2, iface: 
org.bluez.GattDescriptor1
bluetoothd[16877]: src/gatt-database.c:proxy_added_cb() Object received: 
/org/bluez/example/service2/char0, iface: org.bluez.GattCharacteristic1
bluetoothd[16877]: src/gatt-database.c:client_ready_cb() # 
client_ready_cb
bluetoothd[16877]: src/gatt-database.c:create_service() # create_service 
from /org/bluez/example/service2
bluetoothd[16877]: src/gatt-database.c:create_service() # create_service 
from /org/bluez/example/service1
bluetoothd[16877]: src/gatt-database.c:create_service() # create_service 
from /org/bluez/example/service0
bluetoothd[16877]: src/gatt-database.c:database_add_app() # 
database_add_app
bluetoothd[16877]: src/gatt-database.c:database_add_service() # 
database_add_service
bluetoothd[16877]: src/gatt-database.c:cep_write_cb() Stored CEP value 
in the database
bluetoothd[16877]: src/gatt-database.c:database_add_cep() Created CEP 
entry for characteristic
bluetoothd[16877]: src/gatt-database.c:cep_write_cb() Stored CEP value 
in the database
bluetoothd[16877]: src/gatt-database.c:database_add_cep() Created CEP 
entry for characteristic
bluetoothd[16877]: src/gatt-database.c:cep_write_cb() Stored CEP value 
in the database
bluetoothd[16877]: src/gatt-database.c:database_add_cep() Created CEP 
entry for characteristic
bluetoothd[16877]: src/gatt-database.c:gatt_db_service_added() # 
gatt_db_service_added: GATT Service added to local database
bluetoothd[16877]: src/gatt-database.c:database_add_service() # 
database_add_service
bluetoothd[16877]: src/gatt-database.c:database_add_ccc() Created CCC 
entry for characteristic
bluetoothd[16877]: src/gatt-database.c:gatt_db_service_added() # 
gatt_db_service_added: GATT Service added to local database
bluetoothd[16877]: src/gatt-database.c:database_add_service() # 
database_add_service
bluetoothd[16877]: src/gatt-database.c:database_add_ccc() Created CCC 
entry for characteristic
bluetoothd[16877]: src/gatt-database.c:gatt_db_service_added() # 
gatt_db_service_added: GATT Service added to local database
bluetoothd[16877]: src/gatt-database.c:client_ready_cb() GATT 
application registered: :1.404:/
bluetoothd[16877]: src/advertising.c:parse_service_uuids() Adding 
ServiceUUID: 180D
bluetoothd[16877]: src/advertising.c:parse_service_uuids() Adding 
ServiceUUID: 180F
bluetoothd[16877]: src/advertising.c:parse_manufacturer_data() Adding 
ManufacturerData for ffff
bluetoothd[16877]: src/advertising.c:parse_service_data() Adding 
ServiceData for 9999
bluetoothd[16877]: src/advertising.c:refresh_advertisement() Refreshing 
advertisement: /org/bluez/example/advertisement0
bluetoothd[16877]: src/advertising.c:add_adv_callback() Advertisement 
registered: /org/bluez/example/advertisement0

I start `./test/example-gatt-server` as a normal user. But Bluez does 
not seem to have any permission issue with it.

I am using 'BLE scanner' on Android to discover the GATT services. But I 
think the problem is coming from Bluez. When I connect the Android 
device to Bluez, I can see this log:

bluetoothd[16877]: src/adapter.c:connected_callback() hci0 device 
98:D6:F7:31:7B:0D connected eir_len 14
bluetoothd[16877]: src/gatt-database.c:connect_cb() New incoming BR/EDR 
ATT connection
bluetoothd[16877]: attrib/gattrib.c:g_attrib_ref() 0x98cd908: 
g_attrib_ref=1
bluetoothd[16877]: src/device.c:load_gatt_db() # load_gatt_db: Restoring 
98:D6:F7:31:7B:0D gatt database from file 
'/var/lib/bluetooth/5C:F3:70:6A:D9:3C/cache/98:D6:F7:31:7B:0D'
bluetoothd[16877]: src/device.c:load_gatt_db_impl() # load_gatt_db_impl
bluetoothd[16877]: src/device.c:load_service() # load_service: loading 
service: 0x0001, end: 0x0005, uuid: 00001801-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:load_service() # load_service: loading 
service: 0x0014, end: 0xffff, uuid: 00001800-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:load_chrc() loading characteristic 
handle: 0x0002, value handle: 0x0003, properties 0x0020 uuid: 
00002a05-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:load_chrc() loading characteristic 
handle: 0x0015, value handle: 0x0016, properties 0x0002 uuid: 
00002a00-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:load_chrc() loading characteristic 
handle: 0x0017, value handle: 0x0018, properties 0x0002 uuid: 
00002a01-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:load_gatt_db() List GATT Primaries 
before being free:
bluetoothd[16877]: src/device.c:print_primary() - Primary UUID: 
00001801-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:print_primary() - Primary UUID: 
00001800-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:add_primary() # add_primary
bluetoothd[16877]: src/device.c:add_primary() # add_primary
bluetoothd[16877]: profiles/gap/gas.c:gap_accept() GAP profile accept 
(98:D6:F7:31:7B:0D)
bluetoothd[16877]: src/service.c:change_state() 0x98c98e0: device 
98:D6:F7:31:7B:0D profile gap-profile state changed: disconnected -> 
connected (0)
bluetoothd[16877]: src/gatt-client.c:btd_gatt_client_connected() Device 
connected.
bluetoothd[16877]: src/device.c:gatt_server_init() # gatt_server_init
bluetoothd[16877]: src/device.c:gatt_debug() Primary services found: 2
bluetoothd[16877]: src/device.c:gatt_debug() start: 0x0001, end: 0x0005, 
uuid: 00001801-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:gatt_debug() start: 0x0014, end: 0xffff, 
uuid: 00001800-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:gatt_debug() Registered handler for 
"Service Changed": 0
bluetoothd[16877]: src/device.c:gatt_client_ready_cb() status: success, 
error: 0
bluetoothd[16877]: src/device.c:register_gatt_services() # 
register_gatt_services
bluetoothd[16877]: src/device.c:add_primary() # add_primary
bluetoothd[16877]: src/device.c:add_primary() # add_primary
bluetoothd[16877]: src/device.c:add_gatt_service() # add_gatt_service: 
UUID:00001801-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/gatt-client.c:btd_gatt_client_ready() GATT client 
ready
bluetoothd[16877]: src/gatt-client.c:create_services() Exporting objects 
for GATT services: 98:D6:F7:31:7B:0D
bluetoothd[16877]: src/gatt-client.c:service_create() Exported GATT 
service: /org/bluez/hci0/dev_98_D6_F7_31_7B_0D/service0001
bluetoothd[16877]: src/gatt-client.c:characteristic_create() Exported 
GATT characteristic: 
/org/bluez/hci0/dev_98_D6_F7_31_7B_0D/service0001/char0002
bluetoothd[16877]: src/device.c:device_svc_resolved() 
/org/bluez/hci0/dev_98_D6_F7_31_7B_0D err 0
bluetoothd[16877]: src/device.c:store_gatt_db() # store_gatt_db
bluetoothd[16877]: src/device.c:store_service() # store_service
bluetoothd[16877]: src/device.c:store_service() # store_service
bluetoothd[16877]: profiles/gap/gas.c:read_device_name_cb() GAP Device 
Name: Nexus 4
bluetoothd[16877]: profiles/gap/gas.c:read_appearance_cb() GAP 
Appearance: 0x0000

I also reduced DBus 'TestAdvertisement' interface to only expose one 
GATT Service as many BLE adapter got a limitation in the size of the 
advertisement packet:
class TestAdvertisement(Advertisement):

     def __init__(self, bus, index):
         Advertisement.__init__(self, bus, index, 'peripheral')
         #self.add_service_uuid('180D') # HeartRate
         self.add_service_uuid('180F') # Battery
         #self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 
0x04])
         #self.add_service_data('9999', [0x00, 0x01, 0x02, 0x03, 0x04])
         self.include_tx_power = True

My concern is mainly these lines:

bluetoothd[16877]: src/device.c:gatt_debug() Primary services found: 2
bluetoothd[16877]: src/device.c:gatt_debug() start: 0x0001, end: 0x0005, 
uuid: 00001801-0000-1000-8000-00805f9b34fb
bluetoothd[16877]: src/device.c:gatt_debug() start: 0x0014, end: 0xffff, 
uuid: 00001800-0000-1000-8000-00805f9b34fb

I have not found the code that export GATT Services from GATT Database 
to the BLE central.

 From my search on Internet, it looks I am not the only one who is having 
this issue
I am happy to share/test anything that could help to make some progress.

Thanks,
Olivier

^ permalink raw reply

* Re: [PATCHv4 0/2] Nokia H4+ support
From: Marcel Holtmann @ 2017-04-13  8:33 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Gustavo F. Padovan, Johan Hedberg, Rob Herring, Pavel Machek,
	Linux Bluetooth, devicetree, linux-kernel
In-Reply-To: <20170413002659.25821-1-sre@kernel.org>

Hi Sebastian,

> Here is the fourth revision of the nokia bluetooth patchset. Compared
> to the previous one the following things have changed:
> 
> * Drop patch 1-8 (applied by Marcel) and update Cc/To for patchset
> * Order includes in the driver alphabetically
> * Explicitly include <linux/of.h> in the nokia bluetooth driver
> 
> -- Sebastian
> 
> Sebastian Reichel (2):
>  dt-bindings: net: bluetooth: Add nokia-bluetooth
>  Bluetooth: add nokia driver

both patches have been applied to bluetooth-next tree.

Regards

Marcel

^ permalink raw reply

* Re: [PATCHv4 0/2] cfg80211: mac80211: BTCOEX feature support
From: Johannes Berg @ 2017-04-13  6:32 UTC (permalink / raw)
  To: Tamizh Chelvam Raja, Arend Van Spriel,
	linux-wireless@vger.kernel.org
  Cc: ath10k@lists.infradead.org, tamizhchelvam@codeaurora.org,
	linux-bluetooth@vger.kernel.org, Marcel Holtmann
In-Reply-To: <efe890d95d374af7b7a8839811afe0d8@aphydexm01f.ap.qualcomm.com>

On Wed, 2017-04-12 at 07:08 +0000, Tamizh Chelvam Raja wrote:
> > 
> > So you make a distinction between WMM ACs, but what about the
> > different
> > types/profiles of BT traffic?
> > 
> 
> [Tamizh] There will be BT high and BT low traffic. It will be decided
> by BT module. Firmware internally checks BT low traffic with wlan
> traffic. If we enable some of wlan frames as high priority, those
> frames will have more priority than BT low traffic.

That ("firmware internally..." etc.) really sounds more like an
argument *not* to apply this patch ...

Everyone has their favourite BT coex control. We could possibly
implement this in our driver, but I'm not sure we'd *want* to, since
it's so far from what we actually do today.

Do we really need more than toggling it on/off?

Actually, I probably should've asked this much earlier - but what use
cases do you see for this? What can a user, or userspace application
like NM, really try to set here? It seems the use cases for this would
be rather constrained?

johannes

^ permalink raw reply

* [PATCHv4 2/2] Bluetooth: add nokia driver
From: Sebastian Reichel @ 2017-04-13  0:26 UTC (permalink / raw)
  To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
	Johan Hedberg, Rob Herring
  Cc: Pavel Machek, linux-bluetooth, devicetree, linux-kernel
In-Reply-To: <20170413002659.25821-1-sre@kernel.org>

This adds a driver for the Nokia H4+ protocol, which is used
at least on the Nokia N9, N900 & N950.

Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv1:
 * replace __u8 and uint8_t with u8
 * replace __u16 and uint16_t with u16
 * drop BT_BAUDRATE_DIVIDER and use btdev->sysclk_speed * 10 instead
 * fix wording of a sentence
 * fix error path of negotation & alive package receive functions
 * replaced nokia_wait_for_cts with newly introduced serdev function
 * use "nokia,h4p-bluetooth" as compatible string

Changes since PATCHv3:
 * order includes alphabetically
 * explicitly include <linux/of.h>
---
 drivers/bluetooth/Kconfig     |  12 +
 drivers/bluetooth/Makefile    |   2 +
 drivers/bluetooth/hci_nokia.c | 820 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 834 insertions(+)
 create mode 100644 drivers/bluetooth/hci_nokia.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index c2c14a12713b..2e3e4d3547ad 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -86,6 +86,18 @@ config BT_HCIUART_H4
 
 	  Say Y here to compile support for HCI UART (H4) protocol.
 
+config BT_HCIUART_NOKIA
+	tristate "UART Nokia H4+ protocol support"
+	depends on BT_HCIUART
+	depends on SERIAL_DEV_BUS
+	depends on PM
+	help
+	  Nokia H4+ is serial protocol for communication between Bluetooth
+	  device and host. This protocol is required for Bluetooth devices
+	  with UART interface in Nokia devices.
+
+	  Say Y here to compile support for Nokia's H4+ protocol.
+
 config BT_HCIUART_BCSP
 	bool "BCSP protocol support"
 	depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index fd571689eed6..a7f237320f4b 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -25,6 +25,8 @@ obj-$(CONFIG_BT_BCM)		+= btbcm.o
 obj-$(CONFIG_BT_RTL)		+= btrtl.o
 obj-$(CONFIG_BT_QCA)		+= btqca.o
 
+obj-$(CONFIG_BT_HCIUART_NOKIA)	+= hci_nokia.o
+
 btmrvl-y			:= btmrvl_main.o
 btmrvl-$(CONFIG_DEBUG_FS)	+= btmrvl_debugfs.o
 
diff --git a/drivers/bluetooth/hci_nokia.c b/drivers/bluetooth/hci_nokia.c
new file mode 100644
index 000000000000..4038daf78d24
--- /dev/null
+++ b/drivers/bluetooth/hci_nokia.c
@@ -0,0 +1,820 @@
+/*
+ *  Bluetooth HCI UART H4 driver with Nokia Extensions AKA Nokia H4+
+ *
+ *  Copyright (C) 2015 Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2015-2017 Sebastian Reichel <sre@kernel.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  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.
+ */
+
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/serdev.h>
+#include <linux/skbuff.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned/le_struct.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+#include "btbcm.h"
+
+#define NOKIA_ID_BCM2048	0x04
+#define NOKIA_ID_TI1271		0x31
+
+#define FIRMWARE_BCM2048	"nokia/bcmfw.bin"
+#define FIRMWARE_TI1271		"nokia/ti1273.bin"
+
+#define HCI_NOKIA_NEG_PKT	0x06
+#define HCI_NOKIA_ALIVE_PKT	0x07
+#define HCI_NOKIA_RADIO_PKT	0x08
+
+#define HCI_NOKIA_NEG_HDR_SIZE		1
+#define HCI_NOKIA_MAX_NEG_SIZE		255
+#define HCI_NOKIA_ALIVE_HDR_SIZE	1
+#define HCI_NOKIA_MAX_ALIVE_SIZE	255
+#define HCI_NOKIA_RADIO_HDR_SIZE	2
+#define HCI_NOKIA_MAX_RADIO_SIZE	255
+
+#define NOKIA_PROTO_PKT		0x44
+#define NOKIA_PROTO_BYTE	0x4c
+
+#define NOKIA_NEG_REQ		0x00
+#define NOKIA_NEG_ACK		0x20
+#define NOKIA_NEG_NAK		0x40
+
+#define H4_TYPE_SIZE		1
+
+#define NOKIA_RECV_ALIVE \
+	.type = HCI_NOKIA_ALIVE_PKT, \
+	.hlen = HCI_NOKIA_ALIVE_HDR_SIZE, \
+	.loff = 0, \
+	.lsize = 1, \
+	.maxlen = HCI_NOKIA_MAX_ALIVE_SIZE \
+
+#define NOKIA_RECV_NEG \
+	.type = HCI_NOKIA_NEG_PKT, \
+	.hlen = HCI_NOKIA_NEG_HDR_SIZE, \
+	.loff = 0, \
+	.lsize = 1, \
+	.maxlen = HCI_NOKIA_MAX_NEG_SIZE \
+
+#define NOKIA_RECV_RADIO \
+	.type = HCI_NOKIA_RADIO_PKT, \
+	.hlen = HCI_NOKIA_RADIO_HDR_SIZE, \
+	.loff = 1, \
+	.lsize = 1, \
+	.maxlen = HCI_NOKIA_MAX_RADIO_SIZE \
+
+struct hci_nokia_neg_hdr {
+	u8	dlen;
+} __packed;
+
+struct hci_nokia_neg_cmd {
+	u8	ack;
+	u16	baud;
+	u16	unused1;
+	u8	proto;
+	u16	sys_clk;
+	u16	unused2;
+} __packed;
+
+#define NOKIA_ALIVE_REQ   0x55
+#define NOKIA_ALIVE_RESP  0xcc
+
+struct hci_nokia_alive_hdr {
+	u8	dlen;
+} __packed;
+
+struct hci_nokia_alive_pkt {
+	u8	mid;
+	u8	unused;
+} __packed;
+
+struct hci_nokia_neg_evt {
+	u8	ack;
+	u16	baud;
+	u16	unused1;
+	u8	proto;
+	u16	sys_clk;
+	u16	unused2;
+	u8	man_id;
+	u8	ver_id;
+} __packed;
+
+#define MAX_BAUD_RATE		3692300
+#define SETUP_BAUD_RATE		921600
+#define INIT_BAUD_RATE		120000
+
+struct hci_nokia_radio_hdr {
+	u8	evt;
+	u8	dlen;
+} __packed;
+
+struct nokia_bt_dev {
+	struct hci_uart hu;
+	struct serdev_device *serdev;
+
+	struct gpio_desc *reset;
+	struct gpio_desc *wakeup_host;
+	struct gpio_desc *wakeup_bt;
+	unsigned long sysclk_speed;
+
+	int wake_irq;
+	struct sk_buff *rx_skb;
+	struct sk_buff_head txq;
+	bdaddr_t bdaddr;
+
+	int init_error;
+	struct completion init_completion;
+
+	u8 man_id;
+	u8 ver_id;
+
+	bool initialized;
+	bool tx_enabled;
+	bool rx_enabled;
+};
+
+static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb);
+
+static void nokia_flow_control(struct serdev_device *serdev, bool enable)
+{
+	if (enable) {
+		serdev_device_set_rts(serdev, true);
+		serdev_device_set_flow_control(serdev, true);
+	} else {
+		serdev_device_set_flow_control(serdev, false);
+		serdev_device_set_rts(serdev, false);
+	}
+}
+
+static irqreturn_t wakeup_handler(int irq, void *data)
+{
+	struct nokia_bt_dev *btdev = data;
+	struct device *dev = &btdev->serdev->dev;
+	int wake_state = gpiod_get_value(btdev->wakeup_host);
+
+	if (btdev->rx_enabled == wake_state)
+		return IRQ_HANDLED;
+
+	if (wake_state)
+		pm_runtime_get(dev);
+	else
+		pm_runtime_put(dev);
+
+	btdev->rx_enabled = wake_state;
+
+	return IRQ_HANDLED;
+}
+
+static int nokia_reset(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	int err;
+
+	/* reset routine */
+	gpiod_set_value_cansleep(btdev->reset, 1);
+	gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
+
+	msleep(100);
+
+	/* safety check */
+	err = gpiod_get_value_cansleep(btdev->wakeup_host);
+	if (err == 1) {
+		dev_err(dev, "reset: host wakeup not low!");
+		return -EPROTO;
+	}
+
+	/* flush queue */
+	serdev_device_write_flush(btdev->serdev);
+
+	/* init uart */
+	nokia_flow_control(btdev->serdev, false);
+	serdev_device_set_baudrate(btdev->serdev, INIT_BAUD_RATE);
+
+	gpiod_set_value_cansleep(btdev->reset, 0);
+
+	/* wait for cts */
+	err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
+	if (err < 0) {
+		dev_err(dev, "CTS not received: %d", err);
+		return err;
+	}
+
+	nokia_flow_control(btdev->serdev, true);
+
+	return 0;
+}
+
+static int nokia_send_alive_packet(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	struct hci_nokia_alive_hdr *hdr;
+	struct hci_nokia_alive_pkt *pkt;
+	struct sk_buff *skb;
+	int len;
+
+	init_completion(&btdev->init_completion);
+
+	len = H4_TYPE_SIZE + sizeof(*hdr) + sizeof(*pkt);
+	skb = bt_skb_alloc(len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	hci_skb_pkt_type(skb) = HCI_NOKIA_ALIVE_PKT;
+	memset(skb->data, 0x00, len);
+
+	hdr = (struct hci_nokia_alive_hdr *)skb_put(skb, sizeof(*hdr));
+	hdr->dlen = sizeof(*pkt);
+	pkt = (struct hci_nokia_alive_pkt *)skb_put(skb, sizeof(*pkt));
+	pkt->mid = NOKIA_ALIVE_REQ;
+
+	nokia_enqueue(hu, skb);
+	hci_uart_tx_wakeup(hu);
+
+	dev_dbg(dev, "Alive sent");
+
+	if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
+		msecs_to_jiffies(1000))) {
+		return -ETIMEDOUT;
+	}
+
+	if (btdev->init_error < 0)
+		return btdev->init_error;
+
+	return 0;
+}
+
+static int nokia_send_negotiation(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	struct hci_nokia_neg_cmd *neg_cmd;
+	struct hci_nokia_neg_hdr *neg_hdr;
+	struct sk_buff *skb;
+	int len, err;
+	u16 baud = DIV_ROUND_CLOSEST(btdev->sysclk_speed * 10, SETUP_BAUD_RATE);
+	int sysclk = btdev->sysclk_speed / 1000;
+
+	len = H4_TYPE_SIZE + sizeof(*neg_hdr) + sizeof(*neg_cmd);
+	skb = bt_skb_alloc(len, GFP_KERNEL);
+	if (!skb)
+		return -ENOMEM;
+
+	hci_skb_pkt_type(skb) = HCI_NOKIA_NEG_PKT;
+
+	neg_hdr = (struct hci_nokia_neg_hdr *)skb_put(skb, sizeof(*neg_hdr));
+	neg_hdr->dlen = sizeof(*neg_cmd);
+
+	neg_cmd = (struct hci_nokia_neg_cmd *)skb_put(skb, sizeof(*neg_cmd));
+	neg_cmd->ack = NOKIA_NEG_REQ;
+	neg_cmd->baud = cpu_to_le16(baud);
+	neg_cmd->unused1 = 0x0000;
+	neg_cmd->proto = NOKIA_PROTO_BYTE;
+	neg_cmd->sys_clk = cpu_to_le16(sysclk);
+	neg_cmd->unused2 = 0x0000;
+
+	btdev->init_error = 0;
+	init_completion(&btdev->init_completion);
+
+	nokia_enqueue(hu, skb);
+	hci_uart_tx_wakeup(hu);
+
+	dev_dbg(dev, "Negotiation sent");
+
+	if (!wait_for_completion_interruptible_timeout(&btdev->init_completion,
+		msecs_to_jiffies(10000))) {
+		return -ETIMEDOUT;
+	}
+
+	if (btdev->init_error < 0)
+		return btdev->init_error;
+
+	/* Change to previously negotiated speed. Flow Control
+	 * is disabled until bluetooth adapter is ready to avoid
+	 * broken bytes being received.
+	 */
+	nokia_flow_control(btdev->serdev, false);
+	serdev_device_set_baudrate(btdev->serdev, SETUP_BAUD_RATE);
+	err = serdev_device_wait_for_cts(btdev->serdev, true, 200);
+	if (err < 0) {
+		dev_err(dev, "CTS not received: %d", err);
+		return err;
+	}
+	nokia_flow_control(btdev->serdev, true);
+
+	dev_dbg(dev, "Negotiation successful");
+
+	return 0;
+}
+
+static int nokia_setup_fw(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	const char *fwname;
+	const struct firmware *fw;
+	const u8 *fw_ptr;
+	size_t fw_size;
+	int err;
+
+	dev_dbg(dev, "setup firmware");
+
+	if (btdev->man_id == NOKIA_ID_BCM2048) {
+		fwname = FIRMWARE_BCM2048;
+	} else if (btdev->man_id == NOKIA_ID_TI1271) {
+		fwname = FIRMWARE_TI1271;
+	} else {
+		dev_err(dev, "Unsupported bluetooth device!");
+		return -ENODEV;
+	}
+
+	err = request_firmware(&fw, fwname, dev);
+	if (err < 0) {
+		dev_err(dev, "%s: Failed to load Nokia firmware file (%d)",
+			hu->hdev->name, err);
+		return err;
+	}
+
+	fw_ptr = fw->data;
+	fw_size = fw->size;
+
+	while (fw_size >= 4) {
+		u16 pkt_size = get_unaligned_le16(fw_ptr);
+		u8 pkt_type = fw_ptr[2];
+		const struct hci_command_hdr *cmd;
+		u16 opcode;
+		struct sk_buff *skb;
+
+		switch (pkt_type) {
+		case HCI_COMMAND_PKT:
+			cmd = (struct hci_command_hdr *)(fw_ptr + 3);
+			opcode = le16_to_cpu(cmd->opcode);
+
+			skb = __hci_cmd_sync(hu->hdev, opcode, cmd->plen,
+					     fw_ptr + 3 + HCI_COMMAND_HDR_SIZE,
+					     HCI_INIT_TIMEOUT);
+			if (IS_ERR(skb)) {
+				err = PTR_ERR(skb);
+				dev_err(dev, "%s: FW command %04x failed (%d)",
+				       hu->hdev->name, opcode, err);
+				goto done;
+			}
+			kfree_skb(skb);
+			break;
+		case HCI_NOKIA_RADIO_PKT:
+		case HCI_NOKIA_NEG_PKT:
+		case HCI_NOKIA_ALIVE_PKT:
+			break;
+		}
+
+		fw_ptr += pkt_size + 2;
+		fw_size -= pkt_size + 2;
+	}
+
+done:
+	release_firmware(fw);
+	return err;
+}
+
+static int nokia_setup(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	int err;
+
+	btdev->initialized = false;
+
+	nokia_flow_control(btdev->serdev, false);
+
+	pm_runtime_get_sync(dev);
+
+	if (btdev->tx_enabled) {
+		gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
+		pm_runtime_put(&btdev->serdev->dev);
+		btdev->tx_enabled = false;
+	}
+
+	dev_dbg(dev, "protocol setup");
+
+	/* 0. reset connection */
+	err = nokia_reset(hu);
+	if (err < 0) {
+		dev_err(dev, "Reset failed: %d", err);
+		goto out;
+	}
+
+	/* 1. negotiate speed etc */
+	err = nokia_send_negotiation(hu);
+	if (err < 0) {
+		dev_err(dev, "Negotiation failed: %d", err);
+		goto out;
+	}
+
+	/* 2. verify correct setup using alive packet */
+	err = nokia_send_alive_packet(hu);
+	if (err < 0) {
+		dev_err(dev, "Alive check failed: %d", err);
+		goto out;
+	}
+
+	/* 3. send firmware */
+	err = nokia_setup_fw(hu);
+	if (err < 0) {
+		dev_err(dev, "Could not setup FW: %d", err);
+		goto out;
+	}
+
+	nokia_flow_control(btdev->serdev, false);
+	serdev_device_set_baudrate(btdev->serdev, MAX_BAUD_RATE);
+	nokia_flow_control(btdev->serdev, true);
+
+	if (btdev->man_id == NOKIA_ID_BCM2048) {
+		hu->hdev->set_bdaddr = btbcm_set_bdaddr;
+		set_bit(HCI_QUIRK_INVALID_BDADDR, &hu->hdev->quirks);
+		dev_dbg(dev, "bcm2048 has invalid bluetooth address!");
+	}
+
+	dev_dbg(dev, "protocol setup done!");
+
+	gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
+	pm_runtime_put(dev);
+	btdev->tx_enabled = false;
+	btdev->initialized = true;
+
+	return 0;
+out:
+	pm_runtime_put(dev);
+
+	return err;
+}
+
+static int nokia_open(struct hci_uart *hu)
+{
+	struct device *dev = &hu->serdev->dev;
+
+	dev_dbg(dev, "protocol open");
+
+	serdev_device_open(hu->serdev);
+
+	pm_runtime_enable(dev);
+
+	return 0;
+}
+
+static int nokia_flush(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+
+	dev_dbg(&btdev->serdev->dev, "flush device");
+
+	skb_queue_purge(&btdev->txq);
+
+	return 0;
+}
+
+static int nokia_close(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+
+	dev_dbg(dev, "close device");
+
+	btdev->initialized = false;
+
+	skb_queue_purge(&btdev->txq);
+
+	kfree_skb(btdev->rx_skb);
+
+	/* disable module */
+	gpiod_set_value(btdev->reset, 1);
+	gpiod_set_value(btdev->wakeup_bt, 0);
+
+	pm_runtime_disable(&btdev->serdev->dev);
+	serdev_device_close(btdev->serdev);
+
+	return 0;
+}
+
+/* Enqueue frame for transmittion (padding, crc, etc) */
+static int nokia_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	int err;
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+	/* Packets must be word aligned */
+	if (skb->len % 2) {
+		err = skb_pad(skb, 1);
+		if (err)
+			return err;
+		*skb_put(skb, 1) = 0x00;
+	}
+
+	skb_queue_tail(&btdev->txq, skb);
+
+	return 0;
+}
+
+static int nokia_recv_negotiation_packet(struct hci_dev *hdev,
+					 struct sk_buff *skb)
+{
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	struct hci_nokia_neg_hdr *hdr;
+	struct hci_nokia_neg_evt *evt;
+	int ret = 0;
+
+	hdr = (struct hci_nokia_neg_hdr *)skb->data;
+	if (hdr->dlen != sizeof(*evt)) {
+		btdev->init_error = -EIO;
+		ret = -EIO;
+		goto finish_neg;
+	}
+
+	evt = (struct hci_nokia_neg_evt *)skb_pull(skb, sizeof(*hdr));
+
+	if (evt->ack != NOKIA_NEG_ACK) {
+		dev_err(dev, "Negotiation received: wrong reply");
+		btdev->init_error = -EINVAL;
+		ret = -EINVAL;
+		goto finish_neg;
+	}
+
+	btdev->man_id = evt->man_id;
+	btdev->ver_id = evt->ver_id;
+
+	dev_dbg(dev, "Negotiation received: baud=%u:clk=%u:manu=%u:vers=%u",
+		evt->baud, evt->sys_clk, evt->man_id, evt->ver_id);
+
+finish_neg:
+	complete(&btdev->init_completion);
+	kfree_skb(skb);
+	return ret;
+}
+
+static int nokia_recv_alive_packet(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	struct hci_uart *hu = hci_get_drvdata(hdev);
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	struct hci_nokia_alive_hdr *hdr;
+	struct hci_nokia_alive_pkt *pkt;
+	int ret = 0;
+
+	hdr = (struct hci_nokia_alive_hdr *)skb->data;
+	if (hdr->dlen != sizeof(*pkt)) {
+		dev_err(dev, "Corrupted alive message");
+		btdev->init_error = -EIO;
+		ret = -EIO;
+		goto finish_alive;
+	}
+
+	pkt = (struct hci_nokia_alive_pkt *)skb_pull(skb, sizeof(*hdr));
+
+	if (pkt->mid != NOKIA_ALIVE_RESP) {
+		dev_err(dev, "Alive received: invalid response: 0x%02x!",
+			pkt->mid);
+		btdev->init_error = -EINVAL;
+		ret = -EINVAL;
+		goto finish_alive;
+	}
+
+	dev_dbg(dev, "Alive received");
+
+finish_alive:
+	complete(&btdev->init_completion);
+	kfree_skb(skb);
+	return ret;
+}
+
+static int nokia_recv_radio(struct hci_dev *hdev, struct sk_buff *skb)
+{
+	/* Packets received on the dedicated radio channel are
+	 * HCI events and so feed them back into the core.
+	 */
+	hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
+	return hci_recv_frame(hdev, skb);
+}
+
+/* Recv data */
+static const struct h4_recv_pkt nokia_recv_pkts[] = {
+	{ H4_RECV_ACL,		.recv = hci_recv_frame },
+	{ H4_RECV_SCO,		.recv = hci_recv_frame },
+	{ H4_RECV_EVENT,	.recv = hci_recv_frame },
+	{ NOKIA_RECV_ALIVE,	.recv = nokia_recv_alive_packet },
+	{ NOKIA_RECV_NEG,	.recv = nokia_recv_negotiation_packet },
+	{ NOKIA_RECV_RADIO,	.recv = nokia_recv_radio },
+};
+
+static int nokia_recv(struct hci_uart *hu, const void *data, int count)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	int err;
+
+	if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
+		return -EUNATCH;
+
+	btdev->rx_skb = h4_recv_buf(hu->hdev, btdev->rx_skb, data, count,
+				  nokia_recv_pkts, ARRAY_SIZE(nokia_recv_pkts));
+	if (IS_ERR(btdev->rx_skb)) {
+		err = PTR_ERR(btdev->rx_skb);
+		dev_err(dev, "Frame reassembly failed (%d)", err);
+		btdev->rx_skb = NULL;
+		return err;
+	}
+
+	return count;
+}
+
+static struct sk_buff *nokia_dequeue(struct hci_uart *hu)
+{
+	struct nokia_bt_dev *btdev = hu->priv;
+	struct device *dev = &btdev->serdev->dev;
+	struct sk_buff *result = skb_dequeue(&btdev->txq);
+
+	if (!btdev->initialized)
+		return result;
+
+	if (btdev->tx_enabled == !!result)
+		return result;
+
+	if (result) {
+		pm_runtime_get_sync(dev);
+		gpiod_set_value_cansleep(btdev->wakeup_bt, 1);
+	} else {
+		serdev_device_wait_until_sent(btdev->serdev, 0);
+		gpiod_set_value_cansleep(btdev->wakeup_bt, 0);
+		pm_runtime_put(dev);
+	}
+
+	btdev->tx_enabled = !!result;
+
+	return result;
+}
+
+static const struct hci_uart_proto nokia_proto = {
+	.id		= HCI_UART_NOKIA,
+	.name		= "Nokia",
+	.open		= nokia_open,
+	.close		= nokia_close,
+	.recv		= nokia_recv,
+	.enqueue	= nokia_enqueue,
+	.dequeue	= nokia_dequeue,
+	.flush		= nokia_flush,
+	.setup		= nokia_setup,
+	.manufacturer	= 1,
+};
+
+static int nokia_bluetooth_serdev_probe(struct serdev_device *serdev)
+{
+	struct device *dev = &serdev->dev;
+	struct nokia_bt_dev *btdev;
+	struct clk *sysclk;
+	int err = 0;
+
+	btdev = devm_kzalloc(dev, sizeof(*btdev), GFP_KERNEL);
+	if (!btdev)
+		return -ENOMEM;
+
+	btdev->hu.serdev = btdev->serdev = serdev;
+	serdev_device_set_drvdata(serdev, btdev);
+
+	btdev->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(btdev->reset)) {
+		err = PTR_ERR(btdev->reset);
+		dev_err(dev, "could not get reset gpio: %d", err);
+		return err;
+	}
+
+	btdev->wakeup_host = devm_gpiod_get(dev, "host-wakeup", GPIOD_IN);
+	if (IS_ERR(btdev->wakeup_host)) {
+		err = PTR_ERR(btdev->wakeup_host);
+		dev_err(dev, "could not get host wakeup gpio: %d", err);
+		return err;
+	}
+
+	btdev->wake_irq = gpiod_to_irq(btdev->wakeup_host);
+
+	err = devm_request_threaded_irq(dev, btdev->wake_irq, NULL,
+		wakeup_handler,
+		IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+		"wakeup", btdev);
+	if (err) {
+		dev_err(dev, "could request wakeup irq: %d", err);
+		return err;
+	}
+
+	btdev->wakeup_bt = devm_gpiod_get(dev, "bluetooth-wakeup",
+					   GPIOD_OUT_LOW);
+	if (IS_ERR(btdev->wakeup_bt)) {
+		err = PTR_ERR(btdev->wakeup_bt);
+		dev_err(dev, "could not get BT wakeup gpio: %d", err);
+		return err;
+	}
+
+	sysclk = devm_clk_get(dev, "sysclk");
+	if (IS_ERR(sysclk)) {
+		err = PTR_ERR(sysclk);
+		dev_err(dev, "could not get sysclk: %d", err);
+		return err;
+	}
+
+	clk_prepare_enable(sysclk);
+	btdev->sysclk_speed = clk_get_rate(sysclk);
+	clk_disable_unprepare(sysclk);
+
+	skb_queue_head_init(&btdev->txq);
+
+	btdev->hu.priv = btdev;
+	btdev->hu.alignment = 2; /* Nokia H4+ is word aligned */
+
+	err = hci_uart_register_device(&btdev->hu, &nokia_proto);
+	if (err) {
+		dev_err(dev, "could not register bluetooth uart: %d", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void nokia_bluetooth_serdev_remove(struct serdev_device *serdev)
+{
+	struct nokia_bt_dev *btdev = serdev_device_get_drvdata(serdev);
+	struct hci_uart *hu = &btdev->hu;
+	struct hci_dev *hdev = hu->hdev;
+
+	cancel_work_sync(&hu->write_work);
+
+	hci_unregister_dev(hdev);
+	hci_free_dev(hdev);
+	hu->proto->close(hu);
+
+	pm_runtime_disable(&btdev->serdev->dev);
+}
+
+static int nokia_bluetooth_runtime_suspend(struct device *dev)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+
+	nokia_flow_control(serdev, false);
+	return 0;
+}
+
+static int nokia_bluetooth_runtime_resume(struct device *dev)
+{
+	struct serdev_device *serdev = to_serdev_device(dev);
+
+	nokia_flow_control(serdev, true);
+	return 0;
+}
+
+static const struct dev_pm_ops nokia_bluetooth_pm_ops = {
+	SET_RUNTIME_PM_OPS(nokia_bluetooth_runtime_suspend,
+			   nokia_bluetooth_runtime_resume,
+			   NULL)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id nokia_bluetooth_of_match[] = {
+	{ .compatible = "nokia,h4p-bluetooth", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, nokia_bluetooth_of_match);
+#endif
+
+static struct serdev_device_driver nokia_bluetooth_serdev_driver = {
+	.probe = nokia_bluetooth_serdev_probe,
+	.remove = nokia_bluetooth_serdev_remove,
+	.driver = {
+		.name = "nokia-bluetooth",
+		.pm = &nokia_bluetooth_pm_ops,
+		.of_match_table = of_match_ptr(nokia_bluetooth_of_match),
+	},
+};
+
+module_serdev_device_driver(nokia_bluetooth_serdev_driver);
-- 
2.11.0

^ permalink raw reply related

* [PATCHv4 1/2] dt-bindings: net: bluetooth: Add nokia-bluetooth
From: Sebastian Reichel @ 2017-04-13  0:26 UTC (permalink / raw)
  To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
	Johan Hedberg, Rob Herring
  Cc: Pavel Machek, linux-bluetooth, devicetree, linux-kernel
In-Reply-To: <20170413002659.25821-1-sre@kernel.org>

Add binding document for serial bluetooth chips using
Nokia H4+ protocol.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv1:
 * change compatible strings
 * mention active high/low state for GPIOs
---
 .../devicetree/bindings/net/nokia-bluetooth.txt    | 51 ++++++++++++++++++++++
 1 file changed, 51 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nokia-bluetooth.txt

diff --git a/Documentation/devicetree/bindings/net/nokia-bluetooth.txt b/Documentation/devicetree/bindings/net/nokia-bluetooth.txt
new file mode 100644
index 000000000000..42be7dc9a70b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/nokia-bluetooth.txt
@@ -0,0 +1,51 @@
+Nokia Bluetooth Chips
+---------------------
+
+Nokia phones often come with UART connected bluetooth chips from different
+vendors and modified device API. Those devices speak a protocol named H4+
+(also known as h4p) by Nokia, which is similar to the H4 protocol from the
+Bluetooth standard. In addition to the H4 protocol it specifies two more
+UART status lines for wakeup of UART transceivers to improve power management
+and a few new packet types used to negotiate uart speed.
+
+Required properties:
+
+ - compatible: should contain "nokia,h4p-bluetooth" as well as one of the following:
+   * "brcm,bcm2048-nokia"
+   * "ti,wl1271-bluetooth-nokia"
+ - reset-gpios: GPIO specifier, used to reset the BT module (active low)
+ - bluetooth-wakeup-gpios: GPIO specifier, used to wakeup the BT module (active high)
+ - host-wakeup-gpios: GPIO specifier, used to wakeup the host processor (active high)
+ - clock-names: should be "sysclk"
+ - clocks: should contain a clock specifier for every name in clock-names
+
+Optional properties:
+
+ - None
+
+Example:
+
+/ {
+       /* controlled (enabled/disabled) directly by BT module */
+       bluetooth_clk: vctcxo {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <38400000>;
+       };
+};
+
+&uart2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&uart2_pins>;
+
+       bluetooth {
+               compatible = "ti,wl1271-bluetooth-nokia", "nokia,h4p-bluetooth";
+
+               reset-gpios = <&gpio1 26 GPIO_ACTIVE_LOW>; /* gpio26 */
+               host-wakeup-gpios = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */
+               bluetooth-wakeup-gpios = <&gpio2 5 GPIO_ACTIVE_HIGH>; /* gpio37 */
+
+               clocks = <&bluetooth_clk>;
+               clock-names = "sysclk";
+       };
+};
-- 
2.11.0

^ permalink raw reply related

* [PATCHv4 0/2] Nokia H4+ support
From: Sebastian Reichel @ 2017-04-13  0:26 UTC (permalink / raw)
  To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
	Johan Hedberg, Rob Herring
  Cc: Pavel Machek, linux-bluetooth, devicetree, linux-kernel

Hi,

Here is the fourth revision of the nokia bluetooth patchset. Compared
to the previous one the following things have changed:

 * Drop patch 1-8 (applied by Marcel) and update Cc/To for patchset
 * Order includes in the driver alphabetically
 * Explicitly include <linux/of.h> in the nokia bluetooth driver

-- Sebastian

Sebastian Reichel (2):
  dt-bindings: net: bluetooth: Add nokia-bluetooth
  Bluetooth: add nokia driver

 .../devicetree/bindings/net/nokia-bluetooth.txt    |  51 ++
 drivers/bluetooth/Kconfig                          |  12 +
 drivers/bluetooth/Makefile                         |   2 +
 drivers/bluetooth/hci_nokia.c                      | 820 +++++++++++++++++++++
 4 files changed, 885 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/nokia-bluetooth.txt
 create mode 100644 drivers/bluetooth/hci_nokia.c

-- 
2.11.0

^ permalink raw reply

* Re: [PATCHv3 00/10] Nokia H4+ support
From: Sebastian Reichel @ 2017-04-13  0:26 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Greg Kroah-Hartman, Gustavo F. Padovan, Johan Hedberg,
	Samuel Thibault, Pavel Machek, Tony Lindgren, Jiri Slaby,
	Mark Rutland, open list:BLUETOOTH DRIVERS,
	linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, David S. Miller, Rob Herring
In-Reply-To: <C16140C4-0264-411B-9058-0B9013AAC82F@holtmann.org>

[-- Attachment #1: Type: text/plain, Size: 3561 bytes --]

Hi Marcel,

On Wed, Apr 12, 2017 at 10:19:21PM +0200, Marcel Holtmann wrote:
> Hi Sebastian,
> 
> >>>>>>>> Here is PATCHv3 for the Nokia bluetooth patchset. I addressed all comments from
> >>>>>>>> Rob and Pavel regarding the serdev patches and dropped the *.dts patches, since
> >>>>>>>> they were queued by Tony. I also changed the patch order, so that the serdev
> >>>>>>>> patches come first. All of them have Acked-by from Rob, so I think it makes
> >>>>>>>> sense to merge them to serdev subsystem (now) and provide an immutable branch
> >>>>>>>> for the bluetooth subsystem.
> >>>>>>> 
> >>>>>>> Greg doesn't read cover letters generally and since the serdev patches
> >>>>>>> are Cc rather than To him, he's probably not planning to pick them up.
> >>>>>> 
> >>>>>> I wonder actually if we should merge all of these via bluetooth-next
> >>>>>> tree with proper Ack from Greg. However it would be good to also get
> >>>>>> buy in from Dave for merging this ultimately through net-next.
> >>>>> 
> >>>>> I don't really care where it goes.  I can take the whole thing in my
> >>>>> tty/serial tree now if no one objects and I get an ack from the relevant
> >>>>> maintainers {hint...}
> >>>> 
> >>>> I think it is better if it goes thru BT tree. I have another driver
> >>>> converted that is dependent on this series. There's a couple other
> >>>> serdev changes on the list too, but this shouldn't depend on them.
> >>> 
> >>> Is this waiting for something, or could it be queued to
> >>> bluetooth-next then? It would be nice to finally have
> >>> this in 4.12 :)
> >> 
> >> I would prefer if we can get an ACK from Greg. Then I merge it through the bluetooth-next tree.
> > 
> > Sorry thought this was coming through mine:
> > 	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > 
> > Merge away!
> 
> so I have applied patches 1-8 to bluetooth-next tree.
> 
> The last 2 I left out since they do cause build issues on non-DT
> platforms. We need to be able to build the driver on all platforms
> so that sanity compile checks happen all the time.
> 
>   CC      drivers/bluetooth/hci_nokia.o
> drivers/bluetooth/hci_nokia.c:802:34: error: array type has incomplete element type ‘struct of_device_id’
>  static const struct of_device_id nokia_bluetooth_of_match[] = {
>                                   ^~~~~~~~~~~~~~~~~~~~~~~~
> drivers/bluetooth/hci_nokia.c:803:4: error: field name not in record or union initializer
>   { .compatible = "nokia,h4p-bluetooth", },
>     ^
> drivers/bluetooth/hci_nokia.c:803:4: note: (near initialization for ‘nokia_bluetooth_of_match’)
> drivers/bluetooth/hci_nokia.c:815:21: error: implicit declaration of function ‘of_match_ptr’ [-Werror=implicit-function-declaration]
>    .of_match_table = of_match_ptr(nokia_bluetooth_of_match),
>                      ^~~~~~~~~~~~
> drivers/bluetooth/hci_nokia.c:802:34: warning: ‘nokia_bluetooth_of_match’ defined but not used [-Wunused-variable]
>  static const struct of_device_id nokia_bluetooth_of_match[] = {
>                                   ^~~~~~~~~~~~~~~~~~~~~~~~

Building without CONFIG_OF should work already. Note, that its
actually enabled in your build, since nokia_bluetooth_of_match
is guarded by "#ifdef CONFIG_OF". The actual problem is, that
<linux/of.h> is not included in your build. Looks like it was
implicitly included in my configurations, so I didn't notice.
I will send PATCHv4 with the added include and includes sorted
alphabetically.

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH v2 3/4] bluetooth: hci_uart: add LL protocol serdev driver support
From: Marcel Holtmann @ 2017-04-12 20:20 UTC (permalink / raw)
  To: Rob Herring
  Cc: linux-bluetooth, linux-arm-kernel, Gustavo F. Padovan,
	Johan Hedberg, Mark Rutland, Wei Xu, Eyal Reizer, Satish Patel,
	netdev, devicetree
In-Reply-To: <20170407143516.9945-1-robh@kernel.org>

Hi Rob,

> Turns out that the LL protocol and the TI-ST are the same thing AFAICT.
> The TI-ST adds firmware loading, GPIO control, and shared access for
> NFC, FM radio, etc. For now, we're only implementing what is needed for
> BT. This mirrors other drivers like BCM and Intel, but uses the new
> serdev bus.
> 
> The firmware loading is greatly simplified by using existing
> infrastructure to send commands. It may be a bit slower than the
> original code using synchronous functions, but the real bottleneck is
> likely doing firmware load at 115.2kbps.
> 
> Signed-off-by: Rob Herring <robh@kernel.org>
> Cc: Marcel Holtmann <marcel@holtmann.org>
> Cc: Gustavo Padovan <gustavo@padovan.org>
> Cc: Johan Hedberg <johan.hedberg@gmail.com>
> Cc: linux-bluetooth@vger.kernel.org
> ---
> v2:
> - Use IS_ENABLED() to fix module build
> 
> drivers/bluetooth/hci_ll.c | 261 ++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 260 insertions(+), 1 deletion(-)

can you re-send any missing patch on top of today's bluetooth-next tree.

Regards

Marcel

^ permalink raw reply

* Re: [PATCHv3 00/10] Nokia H4+ support
From: Marcel Holtmann @ 2017-04-12 20:19 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Sebastian Reichel, Gustavo F. Padovan, Johan Hedberg,
	Samuel Thibault, Pavel Machek, Tony Lindgren, Jiri Slaby,
	Mark Rutland, open list:BLUETOOTH DRIVERS,
	linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, David S. Miller, Rob Herring
In-Reply-To: <20170411140637.GA4388@kroah.com>

Hi Sebastian,

>>>>>>>> Here is PATCHv3 for the Nokia bluetooth patchset. I addressed all comments from
>>>>>>>> Rob and Pavel regarding the serdev patches and dropped the *.dts patches, since
>>>>>>>> they were queued by Tony. I also changed the patch order, so that the serdev
>>>>>>>> patches come first. All of them have Acked-by from Rob, so I think it makes
>>>>>>>> sense to merge them to serdev subsystem (now) and provide an immutable branch
>>>>>>>> for the bluetooth subsystem.
>>>>>>> 
>>>>>>> Greg doesn't read cover letters generally and since the serdev patches
>>>>>>> are Cc rather than To him, he's probably not planning to pick them up.
>>>>>> 
>>>>>> I wonder actually if we should merge all of these via bluetooth-next
>>>>>> tree with proper Ack from Greg. However it would be good to also get
>>>>>> buy in from Dave for merging this ultimately through net-next.
>>>>> 
>>>>> I don't really care where it goes.  I can take the whole thing in my
>>>>> tty/serial tree now if no one objects and I get an ack from the relevant
>>>>> maintainers {hint...}
>>>> 
>>>> I think it is better if it goes thru BT tree. I have another driver
>>>> converted that is dependent on this series. There's a couple other
>>>> serdev changes on the list too, but this shouldn't depend on them.
>>> 
>>> Is this waiting for something, or could it be queued to
>>> bluetooth-next then? It would be nice to finally have
>>> this in 4.12 :)
>> 
>> I would prefer if we can get an ACK from Greg. Then I merge it through the bluetooth-next tree.
> 
> Sorry thought this was coming through mine:
> 	Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> 
> Merge away!

so I have applied patches 1-8 to bluetooth-next tree.

The last 2 I left out since they do cause build issues on non-DT platforms. We need to be able to build the driver on all platforms so that sanity compile checks happen all the time.

  CC      drivers/bluetooth/hci_nokia.o
drivers/bluetooth/hci_nokia.c:802:34: error: array type has incomplete element type ‘struct of_device_id’
 static const struct of_device_id nokia_bluetooth_of_match[] = {
                                  ^~~~~~~~~~~~~~~~~~~~~~~~
drivers/bluetooth/hci_nokia.c:803:4: error: field name not in record or union initializer
  { .compatible = "nokia,h4p-bluetooth", },
    ^
drivers/bluetooth/hci_nokia.c:803:4: note: (near initialization for ‘nokia_bluetooth_of_match’)
drivers/bluetooth/hci_nokia.c:815:21: error: implicit declaration of function ‘of_match_ptr’ [-Werror=implicit-function-declaration]
   .of_match_table = of_match_ptr(nokia_bluetooth_of_match),
                     ^~~~~~~~~~~~
drivers/bluetooth/hci_nokia.c:802:34: warning: ‘nokia_bluetooth_of_match’ defined but not used [-Wunused-variable]
 static const struct of_device_id nokia_bluetooth_of_match[] = {
                                  ^~~~~~~~~~~~~~~~~~~~~~~~

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 1/6] 6lowpan: Don't set IFF_NO_QUEUE
From: Marcel Holtmann @ 2017-04-12 19:58 UTC (permalink / raw)
  To: Luiz Augusto von Dentz
  Cc: Linux Bluetooth, Patrik Flykt, Alexander Aring, Jukka Rissanen,
	linux-wpan
In-Reply-To: <20170411192103.3209-1-luiz.dentz@gmail.com>

Hi Luiz,

> There is no point in setting IFF_NO_QUEUE should already have taken
> care of setting it if tx_queue_len is not set, in fact this may
> actually disable queue for interfaces that require it and do set
> tx_queue_len.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
> net/6lowpan/core.c | 1 -
> 1 file changed, 1 deletion(-)

all 6 patches have been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH 6/6] bluetooth: Do not set IFF_POINTOPOINT
From: Jukka Rissanen @ 2017-04-12 13:58 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-6-luiz.dentz@gmail.com>


On Tue, 2017-04-11 at 22:21 +0300, Luiz Augusto von Dentz wrote:
> From: Patrik Flykt <patrik.flykt@linux.intel.com>
> 
> The IPv6 stack needs to send and receive Neighbor Discovery
> messages. Remove the IFF_POINTOPOINT flag.
> 
> Signed-off-by: Patrik Flykt <patrik.flykt@linux.intel.com>
> Reviewed-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/bluetooth/6lowpan.c | 3 +--
>  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index a4deba6..6089599 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -592,8 +592,7 @@ static void netdev_setup(struct net_device *dev)
>  {
>  	dev->hard_header_len	= 0;
>  	dev->needed_tailroom	= 0;
> -	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT |
> -				  IFF_MULTICAST;
> +	dev->flags		= IFF_RUNNING | IFF_MULTICAST;
>  	dev->watchdog_timeo	= 0;
>  	dev->tx_queue_len	= DEFAULT_TX_QUEUE_LEN;
>  


Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka


^ permalink raw reply

* Re: [PATCH 5/6] Bluetooth: 6lowpan: Set tx_queue_len to DEFAULT_TX_QUEUE_LEN
From: Jukka Rissanen @ 2017-04-12 13:58 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-5-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, 2017-04-11 at 22:21 +0300, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> Make netdev queue packets if we run out of credits.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/bluetooth/6lowpan.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index dc7fda3..a4deba6 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -20,6 +20,7 @@
>  #include <net/ipv6.h>
>  #include <net/ip6_route.h>
>  #include <net/addrconf.h>
> +#include <net/pkt_sched.h>
>  
>  #include <net/bluetooth/bluetooth.h>
>  #include <net/bluetooth/hci_core.h>
> @@ -594,6 +595,7 @@ static void netdev_setup(struct net_device *dev)
>  	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT |
>  				  IFF_MULTICAST;
>  	dev->watchdog_timeo	= 0;
> +	dev->tx_queue_len	= DEFAULT_TX_QUEUE_LEN;
>  
>  	dev->netdev_ops		= &netdev_ops;
>  	dev->header_ops		= &header_ops;


Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka


^ permalink raw reply

* Re: [PATCH 4/6] Bluetooth: L2CAP: Add l2cap_le_flowctl_send
From: Jukka Rissanen @ 2017-04-12 13:57 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-4-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, 2017-04-11 at 22:21 +0300, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> Consolidate code sending data to LE CoC channels and adds proper
> accounting of packets sent, the remaining credits and how many
> packets
> are queued.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/bluetooth/l2cap_core.c | 27 +++++++++++++++++++--------
>  1 file changed, 19 insertions(+), 8 deletions(-)
> 
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 3a202b0..f88ac995 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -2425,6 +2425,22 @@ static int l2cap_segment_le_sdu(struct
> l2cap_chan *chan,
>  	return 0;
>  }
>  
> +static void l2cap_le_flowctl_send(struct l2cap_chan *chan)
> +{
> +	int sent = 0;
> +
> +	BT_DBG("chan %p", chan);
> +
> +	while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
> +		l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
> +		chan->tx_credits--;
> +		sent++;
> +	}
> +
> +	BT_DBG("Sent %d credits %u queued %u", sent, chan-
> >tx_credits,
> +	       skb_queue_len(&chan->tx_q));
> +}
> +
>  int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg,
> size_t len)
>  {
>  	struct sk_buff *skb;
> @@ -2472,10 +2488,7 @@ int l2cap_chan_send(struct l2cap_chan *chan,
> struct msghdr *msg, size_t len)
>  
>  		skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
>  
> -		while (chan->tx_credits && !skb_queue_empty(&chan-
> >tx_q)) {
> -			l2cap_do_send(chan, skb_dequeue(&chan-
> >tx_q));
> -			chan->tx_credits--;
> -		}
> +		l2cap_le_flowctl_send(chan);
>  
>  		if (!chan->tx_credits)
>  			chan->ops->suspend(chan);
> @@ -5567,10 +5580,8 @@ static inline int l2cap_le_credits(struct
> l2cap_conn *conn,
>  
>  	chan->tx_credits += credits;
>  
> -	while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
> -		l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
> -		chan->tx_credits--;
> -	}
> +	/* Resume sending */
> +	l2cap_le_flowctl_send(chan);
>  
>  	if (chan->tx_credits)
>  		chan->ops->resume(chan);

Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka


^ permalink raw reply

* Re: [PATCH 3/6] Bluetooth: 6lowpan: Use netif APIs to flow control
From: Jukka Rissanen @ 2017-04-12 13:57 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-3-luiz.dentz@gmail.com>

Hi Luiz,


On Tue, 2017-04-11 at 22:21 +0300, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> Rely on netif_wake_queue and netif_stop_queue to flow control when
> transmit resources are unavailable.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/bluetooth/6lowpan.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 22bd936..dc7fda3 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -867,12 +867,28 @@ static struct sk_buff *chan_alloc_skb_cb(struct
> l2cap_chan *chan,
>  
>  static void chan_suspend_cb(struct l2cap_chan *chan)
>  {
> +	struct lowpan_btle_dev *dev;
> +
>  	BT_DBG("chan %p suspend", chan);
> +
> +	dev = lookup_dev(chan->conn);
> +	if (!dev || !dev->netdev)
> +		return;
> +
> +	netif_stop_queue(dev->netdev);
>  }
>  
>  static void chan_resume_cb(struct l2cap_chan *chan)
>  {
> +	struct lowpan_btle_dev *dev;
> +
>  	BT_DBG("chan %p resume", chan);
> +
> +	dev = lookup_dev(chan->conn);
> +	if (!dev || !dev->netdev)
> +		return;
> +
> +	netif_wake_queue(dev->netdev);
>  }
>  
>  static long chan_get_sndtimeo_cb(struct l2cap_chan *chan)


Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka



^ permalink raw reply

* Re: [PATCH 2/6] Bluetooth: 6lowpan: Don't drop packets when run out of credits
From: Jukka Rissanen @ 2017-04-12 13:56 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-2-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, 2017-04-11 at 22:20 +0300, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> Since l2cap_chan_send will now queue the packets there is no point in
> checking the credits anymore.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/bluetooth/6lowpan.c | 11 ++---------
>  1 file changed, 2 insertions(+), 9 deletions(-)
> 
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 5b91e85..22bd936 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -478,15 +478,8 @@ static int send_pkt(struct l2cap_chan *chan,
> struct sk_buff *skb,
>  		return 0;
>  	}
>  
> -	if (!err)
> -		err = (!chan->tx_credits ? -EAGAIN : 0);
> -
> -	if (err < 0) {
> -		if (err == -EAGAIN)
> -			netdev->stats.tx_dropped++;
> -		else
> -			netdev->stats.tx_errors++;
> -	}
> +	if (err < 0)
> +		netdev->stats.tx_errors++;
>  
>  	return err;
>  }


Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka


^ permalink raw reply

* Re: [PATCH 1/6] 6lowpan: Don't set IFF_NO_QUEUE
From: Jukka Rissanen @ 2017-04-12 13:55 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth; +Cc: patrik.flykt, aar, linux-wpan
In-Reply-To: <20170411192103.3209-1-luiz.dentz@gmail.com>

Hi Luiz,

On Tue, 2017-04-11 at 22:20 +0300, Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> 
> There is no point in setting IFF_NO_QUEUE should already have taken
> care of setting it if tx_queue_len is not set, in fact this may
> actually disable queue for interfaces that require it and do set
> tx_queue_len.
> 
> Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
> ---
>  net/6lowpan/core.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
> index 5f9909a..40d3d72 100644
> --- a/net/6lowpan/core.c
> +++ b/net/6lowpan/core.c
> @@ -35,7 +35,6 @@ int lowpan_register_netdevice(struct net_device
> *dev,
>  
>  	dev->type = ARPHRD_6LOWPAN;
>  	dev->mtu = IPV6_MIN_MTU;
> -	dev->priv_flags |= IFF_NO_QUEUE;
>  
>  	lowpan_dev(dev)->lltype = lltype;
>  

Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>


Cheers,
Jukka


^ permalink raw reply

* [PATCH BlueZ v2 5/5] monitor: Add LE PHY update complete event decoding
From: Łukasz Rymanowski @ 2017-04-12 12:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412124127.31486-1-lukasz.rymanowski@codecoup.pl>

---
 monitor/bt.h     |  8 ++++++++
 monitor/packet.c | 13 ++++++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index d6e0046..b3de08c 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2763,6 +2763,14 @@ struct bt_hci_evt_le_direct_adv_report {
 	int8_t   rssi;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE	0x0c
+struct bt_hci_evt_le_phy_update_complete {
+	uint8_t  status;
+	uint16_t handle;
+	uint8_t  tx_phy;
+	uint8_t  rx_phy;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_LE_CHAN_SELECT_ALG		0x14
 struct bt_hci_evt_le_chan_select_alg {
 	uint16_t handle;
diff --git a/monitor/packet.c b/monitor/packet.c
index 61bc92d..3c43356 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -8695,6 +8695,16 @@ static void le_direct_adv_report_evt(const void *data, uint8_t size)
 		packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
 }
 
+static void le_phy_update_complete_evt(const void *data, uint8_t size)
+{
+	const struct bt_hci_evt_le_phy_update_complete *evt = data;
+
+	print_status(evt->status);
+	print_handle(evt->handle);
+	print_le_phy("TX PHY", evt->tx_phy);
+	print_le_phy("RX PHY", evt->rx_phy);
+}
+
 static void le_chan_select_alg_evt(const void *data, uint8_t size)
 {
 	const struct bt_hci_evt_le_chan_select_alg *evt = data;
@@ -8769,7 +8779,8 @@ static const struct subevent_data le_meta_event_table[] = {
 				le_enhanced_conn_complete_evt, 30, true },
 	{ 0x0b, "LE Direct Advertising Report",
 				le_direct_adv_report_evt, 1, false },
-	{ 0x0c, "LE PHY Update Complete" },
+	{ 0x0c, "LE PHY Update Complete",
+				le_phy_update_complete_evt, 5, true},
 	{ 0x0d, "LE Extended Advertising Report" },
 	{ 0x0e, "LE Periodic Advertising Sync Established" },
 	{ 0x0f, "LE Periodic Advertising Report" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ v2 4/5] monitor: Add LE Set PHY decoding
From: Łukasz Rymanowski @ 2017-04-12 12:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412124127.31486-1-lukasz.rymanowski@codecoup.pl>

< HCI Command: LE Set PHY (0x08|0x0032) plen 7
        Handle: 1
        All PHYs preference: 0x00
        TX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        RX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        PHY options preference: S8 coding (0x0002)
---
 monitor/bt.h     |  9 +++++++++
 monitor/packet.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index 9dd726e..d6e0046 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2152,6 +2152,15 @@ struct bt_hci_cmd_le_set_default_phy {
 	uint8_t rx_phys;
 } __attribute__((packed));
 
+#define BT_HCI_CMD_LE_SET_PHY			0x2032
+struct bt_hci_cmd_le_set_phy {
+	uint16_t handle;
+	uint8_t all_phys;
+	uint8_t tx_phys;
+	uint8_t rx_phys;
+	uint16_t phy_opts;
+} __attribute__((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
diff --git a/monitor/packet.c b/monitor/packet.c
index f8b42ac..61bc92d 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6795,16 +6795,16 @@ static const struct {
 	{ }
 };
 
-static void le_set_default_phy_cmd(const void *data, uint8_t size)
+static void print_le_phys_preference(uint8_t all_phys, uint8_t tx_phys,
+							uint8_t rx_phys)
 {
-	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
 	int i;
-	uint8_t mask = cmd->all_phys;
+	uint8_t mask = all_phys;
 
-	print_field("All PHYs preference: 0x%2.2x", cmd->all_phys);
+	print_field("All PHYs preference: 0x%2.2x", all_phys);
 
 	for (i = 0; le_phy_preference[i].str; i++) {
-		if (cmd->all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
+		if (all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
 			print_field("  %s", le_phy_preference[i].str);
 			mask &= ~(((uint64_t) 1) << le_phy_preference[i].bit);
 		}
@@ -6814,11 +6814,11 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
 							" (0x%2.2x)", mask);
 
-	print_field("TX PHYs preference: 0x%2.2x", cmd->tx_phys);
-	mask = cmd->tx_phys;
+	print_field("TX PHYs preference: 0x%2.2x", tx_phys);
+	mask = tx_phys;
 
 	for (i = 0; le_phys[i].str; i++) {
-		if (cmd->tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+		if (tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
 			print_field("  %s", le_phys[i].str);
 			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
 		}
@@ -6828,11 +6828,11 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
 							" (0x%2.2x)", mask);
 
-	print_field("RX PHYs preference: 0x%2.2x", cmd->rx_phys);
-	mask = cmd->rx_phys;
+	print_field("RX PHYs preference: 0x%2.2x", rx_phys);
+	mask = rx_phys;
 
 	for (i = 0; le_phys[i].str; i++) {
-		if (cmd->rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+		if (rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
 			print_field("  %s", le_phys[i].str);
 			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
 		}
@@ -6843,6 +6843,35 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 							" (0x%2.2x)", mask);
 }
 
+static void le_set_default_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
+
+	print_le_phys_preference(cmd->all_phys, cmd->tx_phys, cmd->rx_phys);
+}
+
+static void le_set_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_phy *cmd = data;
+	const char *str;
+
+	print_handle(cmd->handle);
+	print_le_phys_preference(cmd->all_phys, cmd->tx_phys, cmd->rx_phys);
+	switch (le16_to_cpu(cmd->phy_opts)) {
+	case 0x0001:
+		str = "S2 coding";
+		break;
+	case 0x0002:
+		str = "S8 coding";
+		break;
+	default:
+		str = "Reserved";
+		break;
+	}
+
+	print_field("PHY options preference: %s (0x%4.4x)", str, cmd->phy_opts);
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -7543,7 +7572,8 @@ static const struct opcode_data opcode_table[] = {
 				le_read_phy_rsp, 5, true},
 	{ 0x2031, 285, "LE Set Default PHY",
 				le_set_default_phy_cmd, 3, true},
-	{ 0x2032, 286, "LE Set PHY" },
+	{ 0x2032, 286, "LE Set PHY",
+				le_set_phy_cmd, 7, true},
 	{ 0x2033, 287, "LE Enhanced Receiver Test" },
 	{ 0x2034, 288, "LE Enhanced Transmitter Test" },
 	{ 0x2035, 289, "LE Set Advertising Set Random Address" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ v2 3/5] monitor: Add LE Set default PHY decoding
From: Łukasz Rymanowski @ 2017-04-12 12:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412124127.31486-1-lukasz.rymanowski@codecoup.pl>

< HCI Command: LE Set Default PHY (0x08|0x0031) plen 3
        All PHYs preference: 0x00
        TX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        RX PHYs preference: 0x0e
          LE 2M
          LE Coded
          Reserved (0x08)

< HCI Command: LE Set Default PHY (0x08|0x0031) plen 3
        All PHYs preference: 0x03
          No TX PHY preference
          No RX PHY preference
        TX PHYs preference: 0x00
        RX PHYs preference: 0x00
---
 monitor/bt.h     |  7 ++++++
 monitor/packet.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index a6c12a3..9dd726e 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2145,6 +2145,13 @@ struct bt_hci_rsp_le_read_phy {
 	uint8_t rx_phy;
 } __attribute__((packed));
 
+#define BT_HCI_CMD_LE_SET_DEFAULT_PHY		0x2031
+struct bt_hci_cmd_le_set_default_phy {
+	uint8_t all_phys;
+	uint8_t tx_phys;
+	uint8_t rx_phys;
+} __attribute__((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
diff --git a/monitor/packet.c b/monitor/packet.c
index 673b571..f8b42ac 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6776,6 +6776,73 @@ static void le_read_phy_rsp(const void *data, uint8_t size)
 	print_le_phy("RX PHY", rsp->rx_phy);
 }
 
+static const struct {
+	uint8_t bit;
+	const char *str;
+} le_phys[] = {
+	{  0, "LE 1M"	},
+	{  1, "LE 2M"	},
+	{  2, "LE Coded"},
+	{ }
+};
+
+static const struct {
+	uint8_t bit;
+	const char *str;
+} le_phy_preference[] = {
+	{  0, "No TX PHY preference"	},
+	{  1, "No RX PHY preference"	},
+	{ }
+};
+
+static void le_set_default_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
+	int i;
+	uint8_t mask = cmd->all_phys;
+
+	print_field("All PHYs preference: 0x%2.2x", cmd->all_phys);
+
+	for (i = 0; le_phy_preference[i].str; i++) {
+		if (cmd->all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
+			print_field("  %s", le_phy_preference[i].str);
+			mask &= ~(((uint64_t) 1) << le_phy_preference[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+
+	print_field("TX PHYs preference: 0x%2.2x", cmd->tx_phys);
+	mask = cmd->tx_phys;
+
+	for (i = 0; le_phys[i].str; i++) {
+		if (cmd->tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+			print_field("  %s", le_phys[i].str);
+			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+
+	print_field("RX PHYs preference: 0x%2.2x", cmd->rx_phys);
+	mask = cmd->rx_phys;
+
+	for (i = 0; le_phys[i].str; i++) {
+		if (cmd->rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+			print_field("  %s", le_phys[i].str);
+			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -7474,7 +7541,8 @@ static const struct opcode_data opcode_table[] = {
 	{ 0x2030, 284, "LE Read PHY",
 				le_read_phy_cmd, 2, true,
 				le_read_phy_rsp, 5, true},
-	{ 0x2031, 285, "LE Set Default PHY" },
+	{ 0x2031, 285, "LE Set Default PHY",
+				le_set_default_phy_cmd, 3, true},
 	{ 0x2032, 286, "LE Set PHY" },
 	{ 0x2033, 287, "LE Enhanced Receiver Test" },
 	{ 0x2034, 288, "LE Enhanced Transmitter Test" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ v2 2/5] monitor: Add LE Read PHY decoding
From: Łukasz Rymanowski @ 2017-04-12 12:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412124127.31486-1-lukasz.rymanowski@codecoup.pl>

---
 monitor/bt.h     | 11 +++++++++++
 monitor/packet.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 1 deletion(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index 0b77a10..a6c12a3 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2134,6 +2134,17 @@ struct bt_hci_rsp_le_read_max_data_length {
 	uint16_t max_rx_time;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_LE_READ_PHY			0x2030
+struct bt_hci_cmd_le_read_phy {
+	uint16_t handle;
+} __attribute__((packed));
+struct bt_hci_rsp_le_read_phy {
+	uint8_t status;
+	uint16_t handle;
+	uint8_t tx_phy;
+	uint8_t rx_phy;
+} __attribute__((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
diff --git a/monitor/packet.c b/monitor/packet.c
index 219542e..673b571 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6737,6 +6737,45 @@ static void le_read_max_data_length_rsp(const void *data, uint8_t size)
 	print_field("Max RX time: %d", le16_to_cpu(rsp->max_rx_time));
 }
 
+static void le_read_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_read_phy *cmd = data;
+
+	print_handle(cmd->handle);
+}
+
+static void print_le_phy(const char *prefix, uint8_t phy)
+{
+	const char *str;
+
+	switch (phy) {
+	case 0x01:
+		str = "LE 1M";
+		break;
+	case 0x02:
+		str = "LE 2M";
+		break;
+	case 0x03:
+		str = "LE Coded";
+		break;
+	default:
+		str = "Reserved";
+		break;
+	}
+
+	print_field("%s: %s (0x%2.2x)", prefix, str, phy);
+}
+
+static void le_read_phy_rsp(const void *data, uint8_t size)
+{
+	const struct bt_hci_rsp_le_read_phy *rsp = data;
+
+	print_status(rsp->status);
+	print_handle(rsp->handle);
+	print_le_phy("TX PHY", rsp->tx_phy);
+	print_le_phy("RX PHY", rsp->rx_phy);
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -7432,7 +7471,9 @@ static const struct opcode_data opcode_table[] = {
 	{ 0x202f, 283, "LE Read Maximum Data Length",
 				null_cmd, 0, true,
 				le_read_max_data_length_rsp, 9, true },
-	{ 0x2030, 284, "LE Read PHY" },
+	{ 0x2030, 284, "LE Read PHY",
+				le_read_phy_cmd, 2, true,
+				le_read_phy_rsp, 5, true},
 	{ 0x2031, 285, "LE Set Default PHY" },
 	{ 0x2032, 286, "LE Set PHY" },
 	{ 0x2033, 287, "LE Enhanced Receiver Test" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ v2 1/5] monitor: Add description for filter in scan parameters
From: Łukasz Rymanowski @ 2017-04-12 12:41 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski

< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7
        Type: Active (0x01)
        Interval: 30.000 msec (0x0030)
        Window: 30.000 msec (0x0030)
        Own address type: Public (0x00)
        Filter policy: Accept all advertisement, inc. directed unresolved RPA (0x02)
---
 monitor/packet.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/monitor/packet.c b/monitor/packet.c
index 5d927f5..219542e 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6309,6 +6309,12 @@ static void le_set_scan_parameters_cmd(const void *data, uint8_t size)
 	case 0x01:
 		str = "Ignore not in white list";
 		break;
+	case 0x02:
+		str = "Accept all advertisement, inc. directed unresolved RPA";
+		break;
+	case 0x03:
+		str = "Ignore not in white list, exc. directed unresolved RPA";
+		break;
 	default:
 		str = "Reserved";
 		break;
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ 5/5] monitor: Add LE PHY update complete event decoding
From: Łukasz Rymanowski @ 2017-04-12 12:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412121336.783-1-lukasz.rymanowski@codecoup.pl>

---
 monitor/bt.h     |  8 ++++++++
 monitor/packet.c | 13 ++++++++++++-
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index d9701a6..7b14649 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2763,6 +2763,14 @@ struct bt_hci_evt_le_direct_adv_report {
 	int8_t   rssi;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_LE_PHY_UPDATE_COMPLETE	0x0c
+struct bt_hci_evt_le_phy_update_complete {
+	uint8_t  status;
+	uint16_t handle;
+	uint8_t  tx_phy;
+	uint8_t  rx_phy;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_LE_CHAN_SELECT_ALG		0x14
 struct bt_hci_evt_le_chan_select_alg {
 	uint16_t handle;
diff --git a/monitor/packet.c b/monitor/packet.c
index b3ca7c4..5a1ea10 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -8695,6 +8695,16 @@ static void le_direct_adv_report_evt(const void *data, uint8_t size)
 		packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
 }
 
+static void le_phy_update_complete_evt(const void *data, uint8_t size)
+{
+	const struct bt_hci_evt_le_phy_update_complete *evt = data;
+
+	print_status(evt->status);
+	print_handle(evt->handle);
+	print_le_phy("TX PHY", evt->tx_phy);
+	print_le_phy("RX PHY", evt->rx_phy);
+}
+
 static void le_chan_select_alg_evt(const void *data, uint8_t size)
 {
 	const struct bt_hci_evt_le_chan_select_alg *evt = data;
@@ -8769,7 +8779,8 @@ static const struct subevent_data le_meta_event_table[] = {
 				le_enhanced_conn_complete_evt, 30, true },
 	{ 0x0b, "LE Direct Advertising Report",
 				le_direct_adv_report_evt, 1, false },
-	{ 0x0c, "LE PHY Update Complete" },
+	{ 0x0c, "LE PHY Update Complete",
+				le_phy_update_complete_evt, 5, true},
 	{ 0x0d, "LE Extended Advertising Report" },
 	{ 0x0e, "LE Periodic Advertising Sync Established" },
 	{ 0x0f, "LE Periodic Advertising Report" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ 4/5] monitor: Add LE Set PHY decoding
From: Łukasz Rymanowski @ 2017-04-12 12:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412121336.783-1-lukasz.rymanowski@codecoup.pl>

< HCI Command: LE Set PHY (0x08|0x0032) plen 7
        Handle: 1
        All PHYs preference: 0x00
        TX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        RX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        PHY options preference: S8 coding (0x02)
---
 monitor/bt.h     |  9 +++++++++
 monitor/packet.c | 54 ++++++++++++++++++++++++++++++++++++++++++------------
 2 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index 9dd726e..d9701a6 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2152,6 +2152,15 @@ struct bt_hci_cmd_le_set_default_phy {
 	uint8_t rx_phys;
 } __attribute__((packed));
 
+#define BT_HCI_CMD_LE_SET_PHY			0x2032
+struct bt_hci_cmd_le_set_phy {
+	uint16_t handle;
+	uint8_t all_phys;
+	uint8_t tx_phys;
+	uint8_t rx_phys;
+	uint8_t phy_opts;
+} __attribute__((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
diff --git a/monitor/packet.c b/monitor/packet.c
index f8b42ac..b3ca7c4 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6795,16 +6795,16 @@ static const struct {
 	{ }
 };
 
-static void le_set_default_phy_cmd(const void *data, uint8_t size)
+static void print_le_phys_preference(uint8_t all_phys, uint8_t tx_phys,
+							uint8_t rx_phys)
 {
-	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
 	int i;
-	uint8_t mask = cmd->all_phys;
+	uint8_t mask = all_phys;
 
-	print_field("All PHYs preference: 0x%2.2x", cmd->all_phys);
+	print_field("All PHYs preference: 0x%2.2x", all_phys);
 
 	for (i = 0; le_phy_preference[i].str; i++) {
-		if (cmd->all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
+		if (all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
 			print_field("  %s", le_phy_preference[i].str);
 			mask &= ~(((uint64_t) 1) << le_phy_preference[i].bit);
 		}
@@ -6814,11 +6814,11 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
 							" (0x%2.2x)", mask);
 
-	print_field("TX PHYs preference: 0x%2.2x", cmd->tx_phys);
-	mask = cmd->tx_phys;
+	print_field("TX PHYs preference: 0x%2.2x", tx_phys);
+	mask = tx_phys;
 
 	for (i = 0; le_phys[i].str; i++) {
-		if (cmd->tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+		if (tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
 			print_field("  %s", le_phys[i].str);
 			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
 		}
@@ -6828,11 +6828,11 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
 							" (0x%2.2x)", mask);
 
-	print_field("RX PHYs preference: 0x%2.2x", cmd->rx_phys);
-	mask = cmd->rx_phys;
+	print_field("RX PHYs preference: 0x%2.2x", rx_phys);
+	mask = rx_phys;
 
 	for (i = 0; le_phys[i].str; i++) {
-		if (cmd->rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+		if (rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
 			print_field("  %s", le_phys[i].str);
 			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
 		}
@@ -6843,6 +6843,35 @@ static void le_set_default_phy_cmd(const void *data, uint8_t size)
 							" (0x%2.2x)", mask);
 }
 
+static void le_set_default_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
+
+	print_le_phys_preference(cmd->all_phys, cmd->tx_phys, cmd->rx_phys);
+}
+
+static void le_set_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_phy *cmd = data;
+	const char *str;
+
+	print_handle(cmd->handle);
+	print_le_phys_preference(cmd->all_phys, cmd->tx_phys, cmd->rx_phys);
+	switch (cmd->phy_opts) {
+	case 0x01:
+		str = "S2 coding";
+		break;
+	case 0x02:
+		str = "S8 coding";
+		break;
+	default:
+		str = "Reserved";
+		break;
+	}
+
+	print_field("PHY options preference: %s (0x%2.2x)", str, cmd->phy_opts);
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -7543,7 +7572,8 @@ static const struct opcode_data opcode_table[] = {
 				le_read_phy_rsp, 5, true},
 	{ 0x2031, 285, "LE Set Default PHY",
 				le_set_default_phy_cmd, 3, true},
-	{ 0x2032, 286, "LE Set PHY" },
+	{ 0x2032, 286, "LE Set PHY",
+				le_set_phy_cmd, 7, true},
 	{ 0x2033, 287, "LE Enhanced Receiver Test" },
 	{ 0x2034, 288, "LE Enhanced Transmitter Test" },
 	{ 0x2035, 289, "LE Set Advertising Set Random Address" },
-- 
2.9.3


^ permalink raw reply related

* [PATCH BlueZ 3/5] monitor: Add LE Set default PHY decoding
From: Łukasz Rymanowski @ 2017-04-12 12:13 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Łukasz Rymanowski
In-Reply-To: <20170412121336.783-1-lukasz.rymanowski@codecoup.pl>

< HCI Command: LE Set Default PHY (0x08|0x0031) plen 3
        All PHYs preference: 0x00
        TX PHYs preference: 0x07
          LE 1M
          LE 2M
          LE Coded
        RX PHYs preference: 0x0e
          LE 2M
          LE Coded
          Reserved (0x08)

< HCI Command: LE Set Default PHY (0x08|0x0031) plen 3
        All PHYs preference: 0x03
          No TX PHY preference
          No RX PHY preference
        TX PHYs preference: 0x00
        RX PHYs preference: 0x00
---
 monitor/bt.h     |  7 ++++++
 monitor/packet.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/monitor/bt.h b/monitor/bt.h
index a6c12a3..9dd726e 100644
--- a/monitor/bt.h
+++ b/monitor/bt.h
@@ -2145,6 +2145,13 @@ struct bt_hci_rsp_le_read_phy {
 	uint8_t rx_phy;
 } __attribute__((packed));
 
+#define BT_HCI_CMD_LE_SET_DEFAULT_PHY		0x2031
+struct bt_hci_cmd_le_set_default_phy {
+	uint8_t all_phys;
+	uint8_t tx_phys;
+	uint8_t rx_phys;
+} __attribute__((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE		0x01
 struct bt_hci_evt_inquiry_complete {
 	uint8_t  status;
diff --git a/monitor/packet.c b/monitor/packet.c
index 673b571..f8b42ac 100644
--- a/monitor/packet.c
+++ b/monitor/packet.c
@@ -6776,6 +6776,73 @@ static void le_read_phy_rsp(const void *data, uint8_t size)
 	print_le_phy("RX PHY", rsp->rx_phy);
 }
 
+static const struct {
+	uint8_t bit;
+	const char *str;
+} le_phys[] = {
+	{  0, "LE 1M"	},
+	{  1, "LE 2M"	},
+	{  2, "LE Coded"},
+	{ }
+};
+
+static const struct {
+	uint8_t bit;
+	const char *str;
+} le_phy_preference[] = {
+	{  0, "No TX PHY preference"	},
+	{  1, "No RX PHY preference"	},
+	{ }
+};
+
+static void le_set_default_phy_cmd(const void *data, uint8_t size)
+{
+	const struct bt_hci_cmd_le_set_default_phy *cmd = data;
+	int i;
+	uint8_t mask = cmd->all_phys;
+
+	print_field("All PHYs preference: 0x%2.2x", cmd->all_phys);
+
+	for (i = 0; le_phy_preference[i].str; i++) {
+		if (cmd->all_phys & (((uint8_t) 1) << le_phy_preference[i].bit)) {
+			print_field("  %s", le_phy_preference[i].str);
+			mask &= ~(((uint64_t) 1) << le_phy_preference[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+
+	print_field("TX PHYs preference: 0x%2.2x", cmd->tx_phys);
+	mask = cmd->tx_phys;
+
+	for (i = 0; le_phys[i].str; i++) {
+		if (cmd->tx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+			print_field("  %s", le_phys[i].str);
+			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+
+	print_field("RX PHYs preference: 0x%2.2x", cmd->rx_phys);
+	mask = cmd->rx_phys;
+
+	for (i = 0; le_phys[i].str; i++) {
+		if (cmd->rx_phys & (((uint8_t) 1) << le_phys[i].bit)) {
+			print_field("  %s", le_phys[i].str);
+			mask &= ~(((uint64_t) 1) << le_phys[i].bit);
+		}
+	}
+
+	if (mask)
+		print_text(COLOR_UNKNOWN_OPTIONS_BIT, "  Reserved"
+							" (0x%2.2x)", mask);
+}
+
 struct opcode_data {
 	uint16_t opcode;
 	int bit;
@@ -7474,7 +7541,8 @@ static const struct opcode_data opcode_table[] = {
 	{ 0x2030, 284, "LE Read PHY",
 				le_read_phy_cmd, 2, true,
 				le_read_phy_rsp, 5, true},
-	{ 0x2031, 285, "LE Set Default PHY" },
+	{ 0x2031, 285, "LE Set Default PHY",
+				le_set_default_phy_cmd, 3, true},
 	{ 0x2032, 286, "LE Set PHY" },
 	{ 0x2033, 287, "LE Enhanced Receiver Test" },
 	{ 0x2034, 288, "LE Enhanced Transmitter Test" },
-- 
2.9.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox