* [RFC V1 04/16] Bluetooth: hci_ldisc: Add HCI RESET comment to hci_unregister_dev() call
From: Dean Jenkins @ 2017-03-28 17:50 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Dean Jenkins, Gustavo F . Padovan, Johan Hedberg, linux-bluetooth
In-Reply-To: <1490723429-28870-1-git-send-email-Dean_Jenkins@mentor.com>
This commit relates to the HCI UART quirk HCI_QUIRK_RESET_ON_CLOSE
which is enabled by default and can be disabled by setting hdev_flags
flag HCI_UART_RESET_ON_INIT via ioctl HCIUARTSETFLAGS from userland.
The implementation of HCI_QUIRK_RESET_ON_CLOSE is broken for the BCSP
Data Link protocol layer because it can be seen that
hci_unregister_dev() takes 2 seconds to run due to BCSP communications
failure. Suspect that sending of the HCI RESET command is broken
for the other Data Link protocols as well.
Therefore, add a comment to inform that the call to
hci_unregister_dev() in hci_uart_tty_close() may send a HCI RESET
command. This transmission needs the HCI UART driver to remain
operational including having the Data Link protocol being bound to
the HCI UART driver. If the transmission fails, then
hci_unregister_dev() waits HCI_CMD_TIMEOUT (2) seconds for the
timeout to occur which is undesirable.
The current software has a call to hci_unregister_dev(hdev) in
hci_uart_tty_close() which can cause an attempt at sending the
command HCI RESET to occur through the following callstack:
hci_uart_tty_close()
hci_unregister_dev()
hci_dev_do_close()
__hci_req_sync() to queue up command HCI RESET
which adds a work-item to the hdev->workqueue and waits 2 seconds
for a response
Subsequently
hdev->workqueue runs and processes the work-item by calling
hci_cmd_work()
hci_send_frame()
hci_uart_send_frame() to enqueue into the Data Link protocol layer
No protocol response comes so hci_unregister_dev() takes 2 seconds to
run!
In fact, this hidden transmission of the HCI RESET command is most
likely the root cause of why hci_uart_tty_close() crashed in the past
and was "fixed" with multiple workarounds in the past.
The underlying design flaw is that hci_uart_tty_close() is interfering
with various aspects of transmitting and receiving HCI messages
whilst hci_unregister_dev() is trying to use the Data Link protocol
to send the HCI RESET command. Consequently, the design flaw
causes the Data Link protocol to retransmit as no reply comes from
the Bluetooth Radio module over the UART link.
Over the many years of "fixes", this caused the logic in
hci_uart_tty_close() to become over-complex.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
drivers/bluetooth/hci_ldisc.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 1887ad4..c78c9dc 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -499,6 +499,12 @@ static void hci_uart_tty_close(struct tty_struct *tty)
if (test_and_clear_bit(HCI_UART_PROTO_READY, &hu->flags)) {
if (hdev) {
if (test_bit(HCI_UART_REGISTERED, &hu->flags))
+ /* Note hci_unregister_dev() may try to send
+ * a HCI RESET command. If the transmission
+ * fails then hci_unregister_dev() waits
+ * HCI_CMD_TIMEOUT (2) seconds for the timeout
+ * to occur.
+ */
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
--
2.7.4
^ permalink raw reply related
* [RFC V1 03/16] Bluetooth: hci_ldisc: Add missing clear HCI_UART_PROTO_READY
From: Dean Jenkins @ 2017-03-28 17:50 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Dean Jenkins, Gustavo F . Padovan, Johan Hedberg, linux-bluetooth
In-Reply-To: <1490723429-28870-1-git-send-email-Dean_Jenkins@mentor.com>
Ensure that HCI_UART_PROTO_READY is cleared before close(hu) is
called which closes the Data Link protocol layer.
Therefore, add the missing bit clear of HCI_UART_PROTO_READY to
hci_uart_init_work() so that the flag is cleared when
hci_register_dev fails.
Without the fix, the functions of the Data Link protocol layer could
potentially be accessed after that layer has been closed. This
could lead to a crash as memory would have been freed in that layer.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
drivers/bluetooth/hci_ldisc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index a351cc7..1887ad4 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -187,6 +187,7 @@ static void hci_uart_init_work(struct work_struct *work)
hdev = hu->hdev;
hu->hdev = NULL;
hci_free_dev(hdev);
+ clear_bit(HCI_UART_PROTO_READY, &hu->flags);
hu->proto->close(hu);
return;
}
--
2.7.4
^ permalink raw reply related
* [RFC V1 02/16] Bluetooth: hci_ldisc: Ensure hu->hdev set to NULL before freeing hdev
From: Dean Jenkins @ 2017-03-28 17:50 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Dean Jenkins, Gustavo F . Padovan, Johan Hedberg, linux-bluetooth
In-Reply-To: <1490723429-28870-1-git-send-email-Dean_Jenkins@mentor.com>
When hci_register_dev() fails, hu->hdev should be set to NULL before
freeing hdev. This avoids potential use of hu->hdev after it has been
freed.
This commit sets hu->hdev to NULL before calling hci_free_dev() in error
handling scenarios in hci_uart_init_work() and hci_uart_register_dev().
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
drivers/bluetooth/hci_ldisc.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 3a65414..a351cc7 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -176,6 +176,7 @@ static void hci_uart_init_work(struct work_struct *work)
{
struct hci_uart *hu = container_of(work, struct hci_uart, init_ready);
int err;
+ struct hci_dev *hdev;
if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
return;
@@ -183,8 +184,9 @@ static void hci_uart_init_work(struct work_struct *work)
err = hci_register_dev(hu->hdev);
if (err < 0) {
BT_ERR("Can't register HCI device");
- hci_free_dev(hu->hdev);
+ hdev = hu->hdev;
hu->hdev = NULL;
+ hci_free_dev(hdev);
hu->proto->close(hu);
return;
}
@@ -617,6 +619,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
+ hu->hdev = NULL;
hci_free_dev(hdev);
return -ENODEV;
}
--
2.7.4
^ permalink raw reply related
* [RFC V1 01/16] Bluetooth: hci_ldisc: Add missing return in hci_uart_init_work()
From: Dean Jenkins @ 2017-03-28 17:50 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Dean Jenkins, Gustavo F . Padovan, Johan Hedberg, linux-bluetooth
In-Reply-To: <1490723429-28870-1-git-send-email-Dean_Jenkins@mentor.com>
If hci_register_dev() returns an error in hci_uart_init_work()
then the HCI_UART_REGISTERED bit gets erroneously set due to
a missing return statement. Therefore, add the missing return
statement.
The consequence of the missing return is that the HCI UART is not
registered but HCI_UART_REGISTERED is set which allows the code
to think that hu->hdev is safe to access but hu->hdev has been
freed so could lead to a crash.
Signed-off-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
drivers/bluetooth/hci_ldisc.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 9497c46..3a65414 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -186,6 +186,7 @@ static void hci_uart_init_work(struct work_struct *work)
hci_free_dev(hu->hdev);
hu->hdev = NULL;
hu->proto->close(hu);
+ return;
}
set_bit(HCI_UART_REGISTERED, &hu->flags);
--
2.7.4
^ permalink raw reply related
* [RFC V1 00/16] hci_ldisc hci_uart_tty_close() fixes
From: Dean Jenkins @ 2017-03-28 17:50 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Dean Jenkins, Gustavo F . Padovan, Johan Hedberg, linux-bluetooth
This is RFC patchset V1 which reorganises hci_uart_tty_close() to overcome a
design flaw. I would like some comments on the changes.
Design Flaw
===========
An example callstack is as follows
Have Bluetooth running using a BCSP based UART Bluetooth Radio Module.
Now kill the userland hciattach program by doing
killall hciattach
When hciattach terminates, it calls ioctl TIOCSETD to run:
tty_set_ldisc() takes a tty ref lock via tty_ldisc_lock
tty_ldisc_close()
hci_uart_tty_close()
hci_unregister_dev()
hci_dev_do_close()
__hci_req_sync() which tries to send a HCI RESET command which depends on
HCI_QUIRK_RESET_ON_CLOSE being enabled and that is the default condition.
The design flaw is that in order to send a HCI RESET command the BCSP Data Link
protocol layer must be able to send and receive BCSP frames from the UART port
that is physically connected to the BCSP based UART Bluetooth Radio Module. If
this data "pipe" is broken then BCSP will attempt to retransmit every 250ms
until the BCSP layer is closed. In addition, the HCI RESET command has a 2
second timeout which will block __hci_req_sync() for 2 seconds. Enabling
BT_DBG() shows BCSP attempting to retransmit during hci_uart_tty_close().
Meanwhile, tty_set_ldisc() has a tty ref lock which prevents flush_to_ldisc()
from passing the UART port data to the BCSP layer causing a loss of RX BCSP
frames. Similarly, the hci_uart_tty_wakeup() no longer runs. These commits do
not fix this tty ref lock issue.
This patchset removes hci_ldisc.c hci_uart_tty_close() breakages that prevent
__hci_req_sync() from being successful. There are also race conditions due to
the BCSP timeout handling being asynchronous to the thread running
hci_uart_tty_close() which can cause kernel crashes in particular when BCSP is
already retransmitting due to broken communications. Therefore, disabling
the sending of the HCI RESET command does not prevent some of the races.
Solution
========
Reorganise hci_uart_tty_close() so that hci_unregister_dev() can run with no
interference to the data pipe between the Data Link protocol layer such as BCSP
and the UART driver.
The patchset cleans up the HCI_UART_REGISTERED and HCI_UART_PROTO_READY flag
handling so that:
a) hdev is only valid when HCI_UART_REGISTERED is in the set state.
b) the proto Data Link functions pointers can only be used when
HCI_UART_PROTO_READY is in the set state.
Note that flushing can corrupt any data being sent from BCSP to the UART driver
which is undesirable.
The most important patch is
"Bluetooth: hci_ldisc: Use rwlocking to avoid closing proto races"
which adds rwlocking around the clearing of the flag HCI_UART_PROTO_READY.
This is because the atomic flag HCI_UART_PROTO_READY cannot always prevent a
thread using a Data Link protocol layer function pointer during or after closure
of the Data Link protocol layer. This can result in a kernel crash. Remember
that the BCSP retransmission handling runs in a separate thread and tries to
send a new frame. Therefore there is a small window of a race condition for the
flag HCI_UART_PROTO_READY to be seen in the set state and then calls the
proto function pointer after the Data Link protocol layer has been closed,
resulting in a kernel crash.
Next steps
==========
I am still testing these changes but I would like some feedback on the proposed
changes.
I will reply to any feedback next week.
Thanks.
Dean Jenkins (16):
Bluetooth: hci_ldisc: Add missing return in hci_uart_init_work()
Bluetooth: hci_ldisc: Ensure hu->hdev set to NULL before freeing hdev
Bluetooth: hci_ldisc: Add missing clear HCI_UART_PROTO_READY
Bluetooth: hci_ldisc: Add HCI RESET comment to hci_unregister_dev()
call
Bluetooth: hci_ldisc: Add protocol check to hci_uart_send_frame()
Bluetooth: hci_ldisc: Add protocol check to hci_uart_dequeue()
Bluetooth: hci_ldisc: Add protocol check to hci_uart_tx_wakeup()
Bluetooth: hci_ldisc: Separate flag handling in hci_uart_tty_close()
Bluetooth: hci_ldisc: Tidy-up HCI_UART_REGISTERED in
hci_uart_tty_close()
Bluetooth: hci_ldisc: hci_uart_tty_close() detach tty after last msg
Bluetooth: hci_ldisc: hci_uart_tty_close() move hci_uart_close()
Bluetooth: hci_ldisc: hci_uart_tty_close() move cancel_work_sync()
Bluetooth: hci_ldisc: hci_uart_tty_close() free hu->tx_skb
Bluetooth: hci_ldisc: Simplify flushing
Bluetooth: hci_ldisc: Use rwlocking to avoid closing proto races
Bluetooth: hci_ldisc: Add ioctl_mutex avoiding concurrency
drivers/bluetooth/hci_ldisc.c | 105 ++++++++++++++++++++++++++++++++----------
drivers/bluetooth/hci_uart.h | 3 ++
2 files changed, 84 insertions(+), 24 deletions(-)
--
2.7.4
^ permalink raw reply
* [bluetooth-next:master 25/28] sound/soc//mxs/mxs-saif.c:591:3: note: in expansion of macro 'dev_dbg'
From: kbuild test robot @ 2017-03-28 16:18 UTC (permalink / raw)
To: Harry Morris; +Cc: kbuild-all, linux-bluetooth, Marcel Holtmann
[-- Attachment #1: Type: text/plain, Size: 14097 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
head: 50d1455b61a78d1f2dfca4b3366ac5925fb04838
commit: d931acd575d6a36730192756bf2cbd14c77fa1bc [25/28] ieee802154: Add CA8210 IEEE 802.15.4 device driver
config: m32r-allyesconfig (attached as .config)
compiler: m32r-linux-gcc (GCC) 6.2.0
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout d931acd575d6a36730192756bf2cbd14c77fa1bc
# save the attached .config to linux build tree
make.cross ARCH=m32r
All warnings (new ones prefixed by >>):
In file included from include/linux/dma-mapping.h:6:0,
from drivers/mtd/nand/denali.c:21:
drivers/mtd/nand/denali.c: In function 'denali_nand_timing_set':
>> drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 3 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 5 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 6 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 7 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 8 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 9 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
drivers/mtd/nand/denali.c:503:4: warning: format '%d' expects argument of type 'int', but argument 10 has type 'long unsigned int' [-Wformat=]
"Dump timing register values:\n"
^
include/linux/device.h:1317:51: note: in definition of macro 'dev_info'
#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg)
^~~
--
In file included from include/linux/printk.h:6:0,
from include/linux/kernel.h:13,
from include/linux/list.h:8,
from include/linux/kobject.h:20,
from include/linux/device.h:17,
from include/linux/i2c.h:30,
from include/drm/drm_crtc.h:28,
from include/drm/drm_atomic_helper.h:31,
from drivers/gpu/drm/vc4/vc4_dsi.c:32:
drivers/gpu/drm/vc4/vc4_dsi.c: In function 'vc4_dsi_dump_regs':
include/linux/kern_levels.h:4:18: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:13:19: note: in expansion of macro 'KERN_SOH'
#define KERN_INFO KERN_SOH "6" /* informational */
^~~~~~~~
include/drm/drmP.h:151:16: note: in expansion of macro 'KERN_INFO'
printk##once(KERN_##level "[" DRM_NAME "] " fmt, \
^~~~~
include/drm/drmP.h:156:2: note: in expansion of macro '_DRM_PRINTK'
_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
^~~~~~~~~~~
>> drivers/gpu/drm/vc4/vc4_dsi.c:682:4: note: in expansion of macro 'DRM_INFO'
DRM_INFO("0x%04x (%s): 0x%08x\n",
^~~~~~~~
include/linux/kern_levels.h:4:18: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Wformat=]
#define KERN_SOH "\001" /* ASCII Start Of Header */
^
include/linux/kern_levels.h:13:19: note: in expansion of macro 'KERN_SOH'
#define KERN_INFO KERN_SOH "6" /* informational */
^~~~~~~~
include/drm/drmP.h:151:16: note: in expansion of macro 'KERN_INFO'
printk##once(KERN_##level "[" DRM_NAME "] " fmt, \
^~~~~
include/drm/drmP.h:156:2: note: in expansion of macro '_DRM_PRINTK'
_DRM_PRINTK(, INFO, fmt, ##__VA_ARGS__)
^~~~~~~~~~~
drivers/gpu/drm/vc4/vc4_dsi.c:688:4: note: in expansion of macro 'DRM_INFO'
DRM_INFO("0x%04x (%s): 0x%08x\n",
^~~~~~~~
drivers/gpu/drm/vc4/vc4_dsi.c: In function 'vc4_dsi_debugfs_regs':
>> drivers/gpu/drm/vc4/vc4_dsi.c:710:37: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Wformat=]
seq_printf(m, "0x%04x (%s): 0x%08x\n",
^
drivers/gpu/drm/vc4/vc4_dsi.c:716:37: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Wformat=]
seq_printf(m, "0x%04x (%s): 0x%08x\n",
^
drivers/gpu/drm/vc4/vc4_dsi.c: In function 'vc4_dsi_ulps':
drivers/gpu/drm/vc4/vc4_dsi.c:854:52: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=]
"Timeout waiting for DSI ULPS entry: STAT 0x%08x",
^
drivers/gpu/drm/vc4/vc4_dsi.c:873:52: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=]
"Timeout waiting for DSI STOP entry: STAT 0x%08x",
^
drivers/gpu/drm/vc4/vc4_dsi.c: In function 'vc4_dsi_host_transfer':
drivers/gpu/drm/vc4/vc4_dsi.c:1293:42: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=]
dev_err(&dsi->pdev->dev, "instat: 0x%08x\n",
^
drivers/gpu/drm/vc4/vc4_dsi.c: In function 'vc4_dsi_bind':
drivers/gpu/drm/vc4/vc4_dsi.c:1565:36: warning: format '%x' expects argument of type 'unsigned int', but argument 3 has type 'long unsigned int' [-Wformat=]
dev_err(dev, "Port returned 0x%08x for ID instead of 0x%08x\n",
^
--
In file included from include/linux/printk.h:329:0,
from include/linux/kernel.h:13,
from include/linux/list.h:8,
from include/linux/module.h:9,
from sound/soc//mxs/mxs-saif.c:19:
sound/soc//mxs/mxs-saif.c: In function 'mxs_saif_trigger':
>> sound/soc//mxs/mxs-saif.c:591:22: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Wformat=]
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
>> sound/soc//mxs/mxs-saif.c:591:3: note: in expansion of macro 'dev_dbg'
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
^~~~~~~
sound/soc//mxs/mxs-saif.c:591:22: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Wformat=]
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
>> sound/soc//mxs/mxs-saif.c:591:3: note: in expansion of macro 'dev_dbg'
dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
^~~~~~~
sound/soc//mxs/mxs-saif.c:595:29: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Wformat=]
dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
sound/soc//mxs/mxs-saif.c:595:3: note: in expansion of macro 'dev_dbg'
dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
^~~~~~~
sound/soc//mxs/mxs-saif.c:595:29: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Wformat=]
dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
sound/soc//mxs/mxs-saif.c:595:3: note: in expansion of macro 'dev_dbg'
dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
^~~~~~~
sound/soc//mxs/mxs-saif.c: In function 'mxs_saif_irq':
sound/soc//mxs/mxs-saif.c:703:21: warning: format '%x' expects argument of type 'unsigned int', but argument 4 has type 'long unsigned int' [-Wformat=]
dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
sound/soc//mxs/mxs-saif.c:703:2: note: in expansion of macro 'dev_dbg'
dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
^~~~~~~
sound/soc//mxs/mxs-saif.c:703:21: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Wformat=]
dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
^
include/linux/dynamic_debug.h:134:39: note: in definition of macro 'dynamic_dev_dbg'
__dynamic_dev_dbg(&descriptor, dev, fmt, \
^~~
sound/soc//mxs/mxs-saif.c:703:2: note: in expansion of macro 'dev_dbg'
dev_dbg(saif->dev, "SAIF_CTRL %x SAIF_STAT %x\n",
^~~~~~~
vim +/dev_dbg +591 sound/soc//mxs/mxs-saif.c
f55f14752 Fabio Estevam 2012-11-01 575 __raw_writel(0, saif->base + SAIF_DATA);
2a24f2ce8 Dong Aisheng 2011-07-21 576 } else {
2a24f2ce8 Dong Aisheng 2011-07-21 577 /*
f55f14752 Fabio Estevam 2012-11-01 578 * read data from saif data register to trigger
f55f14752 Fabio Estevam 2012-11-01 579 * the receive.
f55f14752 Fabio Estevam 2012-11-01 580 * For 24-bit format the 32-bit FIFO register stores
f55f14752 Fabio Estevam 2012-11-01 581 * only one channel, so we need to read twice.
f55f14752 Fabio Estevam 2012-11-01 582 * This is also safe for the other non 24-bit formats.
2a24f2ce8 Dong Aisheng 2011-07-21 583 */
2a24f2ce8 Dong Aisheng 2011-07-21 584 __raw_readl(saif->base + SAIF_DATA);
f55f14752 Fabio Estevam 2012-11-01 585 __raw_readl(saif->base + SAIF_DATA);
2a24f2ce8 Dong Aisheng 2011-07-21 586 }
2a24f2ce8 Dong Aisheng 2011-07-21 587
76067540c Dong Aisheng 2011-09-07 588 master_saif->ongoing = 1;
88cf632a1 Markus Pargmann 2013-10-11 589 saif->state = MXS_SAIF_STATE_RUNNING;
76067540c Dong Aisheng 2011-09-07 590
76067540c Dong Aisheng 2011-09-07 @591 dev_dbg(saif->dev, "CTRL 0x%x STAT 0x%x\n",
2a24f2ce8 Dong Aisheng 2011-07-21 592 __raw_readl(saif->base + SAIF_CTRL),
2a24f2ce8 Dong Aisheng 2011-07-21 593 __raw_readl(saif->base + SAIF_STAT));
2a24f2ce8 Dong Aisheng 2011-07-21 594
76067540c Dong Aisheng 2011-09-07 595 dev_dbg(master_saif->dev, "CTRL 0x%x STAT 0x%x\n",
76067540c Dong Aisheng 2011-09-07 596 __raw_readl(master_saif->base + SAIF_CTRL),
76067540c Dong Aisheng 2011-09-07 597 __raw_readl(master_saif->base + SAIF_STAT));
2a24f2ce8 Dong Aisheng 2011-07-21 598 break;
2a24f2ce8 Dong Aisheng 2011-07-21 599 case SNDRV_PCM_TRIGGER_SUSPEND:
:::::: The code at line 591 was first introduced by commit
:::::: 76067540c642b1a14679ab74bd027a074c23e63b ASoC: mxs-saif: add record function
:::::: TO: Dong Aisheng <b29396@freescale.com>
:::::: CC: Mark Brown <broonie@opensource.wolfsonmicro.com>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 42520 bytes --]
^ permalink raw reply
* [bluetooth-next:master 25/28] drivers/clk//samsung/clk-s3c2412.c:28:0: warning: "SWRST" redefined
From: kbuild test robot @ 2017-03-28 16:03 UTC (permalink / raw)
To: Harry Morris; +Cc: kbuild-all, linux-bluetooth, Marcel Holtmann
[-- Attachment #1: Type: text/plain, Size: 4586 bytes --]
tree: https://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next.git master
head: 50d1455b61a78d1f2dfca4b3366ac5925fb04838
commit: d931acd575d6a36730192756bf2cbd14c77fa1bc [25/28] ieee802154: Add CA8210 IEEE 802.15.4 device driver
config: blackfin-allmodconfig (attached as .config)
compiler: bfin-uclinux-gcc (GCC) 6.2.0
reproduce:
wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
git checkout d931acd575d6a36730192756bf2cbd14c77fa1bc
# save the attached .config to linux build tree
make.cross ARCH=blackfin
All warnings (new ones prefixed by >>):
>> drivers/clk//samsung/clk-s3c2412.c:28:0: warning: "SWRST" redefined
#define SWRST 0x30
In file included from arch/blackfin/mach-bf533/include/mach/blackfin.h:16:0,
from arch/blackfin/include/asm/irqflags.h:11,
from include/linux/irqflags.h:15,
from arch/blackfin/include/asm/bitops.h:33,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/asm-generic/bug.h:13,
from arch/blackfin/include/asm/bug.h:71,
from include/linux/bug.h:4,
from include/linux/io.h:23,
from include/linux/clk-provider.h:14,
from drivers/clk//samsung/clk-s3c2412.c:11:
arch/blackfin/mach-bf533/include/mach/defBF532.h:25:0: note: this is the location of the previous definition
#define SWRST 0xFFC00100 /* Software Reset Register (16-bit) */
--
>> drivers/clk//samsung/clk-s3c2443.c:35:0: warning: "SWRST" redefined
#define SWRST 0x44
In file included from arch/blackfin/mach-bf533/include/mach/blackfin.h:16:0,
from arch/blackfin/include/asm/irqflags.h:11,
from include/linux/irqflags.h:15,
from arch/blackfin/include/asm/bitops.h:33,
from include/linux/bitops.h:36,
from include/linux/kernel.h:10,
from include/asm-generic/bug.h:13,
from arch/blackfin/include/asm/bug.h:71,
from include/linux/bug.h:4,
from include/linux/io.h:23,
from include/linux/clk-provider.h:14,
from drivers/clk//samsung/clk-s3c2443.c:11:
arch/blackfin/mach-bf533/include/mach/defBF532.h:25:0: note: this is the location of the previous definition
#define SWRST 0xFFC00100 /* Software Reset Register (16-bit) */
vim +/SWRST +28 drivers/clk//samsung/clk-s3c2412.c
ca2e90ac Heiko Stuebner 2014-02-25 12 #include <linux/of.h>
ca2e90ac Heiko Stuebner 2014-02-25 13 #include <linux/of_address.h>
ca2e90ac Heiko Stuebner 2014-02-25 14 #include <linux/syscore_ops.h>
e317c194 Heiko Stübner 2014-08-19 15 #include <linux/reboot.h>
ca2e90ac Heiko Stuebner 2014-02-25 16
ca2e90ac Heiko Stuebner 2014-02-25 17 #include <dt-bindings/clock/s3c2412.h>
ca2e90ac Heiko Stuebner 2014-02-25 18
ca2e90ac Heiko Stuebner 2014-02-25 19 #include "clk.h"
ca2e90ac Heiko Stuebner 2014-02-25 20 #include "clk-pll.h"
ca2e90ac Heiko Stuebner 2014-02-25 21
ca2e90ac Heiko Stuebner 2014-02-25 22 #define LOCKTIME 0x00
ca2e90ac Heiko Stuebner 2014-02-25 23 #define MPLLCON 0x04
ca2e90ac Heiko Stuebner 2014-02-25 24 #define UPLLCON 0x08
ca2e90ac Heiko Stuebner 2014-02-25 25 #define CLKCON 0x0c
ca2e90ac Heiko Stuebner 2014-02-25 26 #define CLKDIVN 0x14
ca2e90ac Heiko Stuebner 2014-02-25 27 #define CLKSRC 0x1c
e317c194 Heiko Stübner 2014-08-19 @28 #define SWRST 0x30
ca2e90ac Heiko Stuebner 2014-02-25 29
ca2e90ac Heiko Stuebner 2014-02-25 30 /* list of PLLs to be registered */
ca2e90ac Heiko Stuebner 2014-02-25 31 enum s3c2412_plls {
ca2e90ac Heiko Stuebner 2014-02-25 32 mpll, upll,
ca2e90ac Heiko Stuebner 2014-02-25 33 };
ca2e90ac Heiko Stuebner 2014-02-25 34
ca2e90ac Heiko Stuebner 2014-02-25 35 static void __iomem *reg_base;
ca2e90ac Heiko Stuebner 2014-02-25 36
:::::: The code at line 28 was first introduced by commit
:::::: e317c19470f6d690122519bf9ed1c9f21ea11906 clk: samsung: register restart handlers for s3c2412 and s3c2443
:::::: TO: Heiko Stübner <heiko@sntech.de>
:::::: CC: Heiko Stuebner <heiko@sntech.de>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 44971 bytes --]
^ permalink raw reply
* [PATCHv3 10/10] Bluetooth: add nokia driver
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-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
---
drivers/bluetooth/Kconfig | 12 +
drivers/bluetooth/Makefile | 2 +
drivers/bluetooth/hci_nokia.c | 819 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 833 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..c77f04af01bf
--- /dev/null
+++ b/drivers/bluetooth/hci_nokia.c
@@ -0,0 +1,819 @@
+/*
+ * 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/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
+#include <linux/firmware.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/gpio/consumer.h>
+#include <linux/unaligned/le_struct.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <linux/serdev.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
* [PATCHv3 09/10] dt-bindings: net: bluetooth: Add nokia-bluetooth
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-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
* [PATCHv3 08/10] Bluetooth: hci_serdev: allow modular drivers
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
For bluetooth protocol driver only supporting serdev it makes
sense to follow common practice and built them into their own
module.
Such modules need access to hci_uart_register_device and
hci_uart_tx_wakeup for using the common protocol helpers.
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
New patch since patchset v2.
---
drivers/bluetooth/hci_ldisc.c | 1 +
drivers/bluetooth/hci_serdev.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 0ec8a94bd712..17bcbc13623f 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -134,6 +134,7 @@ int hci_uart_tx_wakeup(struct hci_uart *hu)
return 0;
}
+EXPORT_SYMBOL_GPL(hci_uart_tx_wakeup);
static void hci_uart_write_work(struct work_struct *work)
{
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
index 3b8ac0ece3fb..7de0edc0ff8c 100644
--- a/drivers/bluetooth/hci_serdev.c
+++ b/drivers/bluetooth/hci_serdev.c
@@ -353,3 +353,4 @@ int hci_uart_register_device(struct hci_uart *hu,
p->close(hu);
return err;
}
+EXPORT_SYMBOL_GPL(hci_uart_register_device);
--
2.11.0
^ permalink raw reply related
* [PATCHv3 07/10] Bluetooth: hci_serdev: do not open device in hci open
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
The device driver may need to communicate with the UART
device while the Bluetooth device is closed (e.g. due
to interrupts).
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/bluetooth/hci_serdev.c | 12 +++---------
1 file changed, 3 insertions(+), 9 deletions(-)
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
index f5ccb2c7ef92..3b8ac0ece3fb 100644
--- a/drivers/bluetooth/hci_serdev.c
+++ b/drivers/bluetooth/hci_serdev.c
@@ -104,13 +104,9 @@ static void hci_uart_write_work(struct work_struct *work)
/* Initialize device */
static int hci_uart_open(struct hci_dev *hdev)
{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
BT_DBG("%s %p", hdev->name, hdev);
- serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
-
- return serdev_device_open(hu->serdev);
+ return 0;
}
/* Reset device */
@@ -136,15 +132,11 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Close device */
static int hci_uart_close(struct hci_dev *hdev)
{
- struct hci_uart *hu = hci_get_drvdata(hdev);
-
BT_DBG("hdev %p", hdev);
hci_uart_flush(hdev);
hdev->flush = NULL;
- serdev_device_close(hu->serdev);
-
return 0;
}
@@ -289,6 +281,8 @@ int hci_uart_register_device(struct hci_uart *hu,
BT_DBG("");
+ serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
+
err = p->open(hu);
if (err)
return err;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 06/10] Bluetooth: hci_uart: add serdev driver support library
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel, Rob Herring
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
From: Rob Herring <robh@kernel.org>
This adds library functions for serdev based BT drivers. This is largely
copied from hci_ldisc.c and modified to use serdev calls. There's a little
bit of duplication, but I avoided intermixing this as the ldisc code should
eventually go away.
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
Acked-by: Pavel Machek <pavel@ucw.cz>
[Fix style issues reported by Pavel]
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv1:
* Drop FSF address from license section
* Add error message if hu->proto->set_baudrate fails
* Remove useless label/goto in hci_uart_setup
* Use proper kerneldoc for hci_uart_write_wakeup
* Use proper kerneldoc for hci_uart_receive_buf
* Wrap hci_uart_register_device define to get < 80 chars
* Use do..while instead of goto restart in hci_uart_write_work
* The file checkpatch clean now
---
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_serdev.c | 361 +++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/hci_uart.h | 4 +
3 files changed, 366 insertions(+)
create mode 100644 drivers/bluetooth/hci_serdev.c
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 80627187c8b6..fd571689eed6 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -29,6 +29,7 @@ btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
hci_uart-y := hci_ldisc.o
+hci_uart-$(CONFIG_SERIAL_DEV_BUS) += hci_serdev.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
new file mode 100644
index 000000000000..f5ccb2c7ef92
--- /dev/null
+++ b/drivers/bluetooth/hci_serdev.c
@@ -0,0 +1,361 @@
+/*
+ * Bluetooth HCI serdev driver lib
+ *
+ * Copyright (C) 2017 Linaro, Ltd., Rob Herring <robh@kernel.org>
+ *
+ * Based on hci_ldisc.c:
+ *
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.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/kernel.h>
+#include <linux/types.h>
+#include <linux/serdev.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+struct serdev_device_ops hci_serdev_client_ops;
+
+static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
+{
+ struct hci_dev *hdev = hu->hdev;
+
+ /* Update HCI stat counters */
+ switch (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;
+ }
+}
+
+static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu)
+{
+ struct sk_buff *skb = hu->tx_skb;
+
+ if (!skb)
+ skb = hu->proto->dequeue(hu);
+ else
+ hu->tx_skb = NULL;
+
+ return skb;
+}
+
+static void hci_uart_write_work(struct work_struct *work)
+{
+ struct hci_uart *hu = container_of(work, struct hci_uart, write_work);
+ struct serdev_device *serdev = hu->serdev;
+ struct hci_dev *hdev = hu->hdev;
+ struct sk_buff *skb;
+
+ /* REVISIT:
+ * should we cope with bad skbs or ->write() returning an error value?
+ */
+ do {
+ clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state);
+
+ while ((skb = hci_uart_dequeue(hu))) {
+ int len;
+
+ len = serdev_device_write_buf(serdev,
+ skb->data, skb->len);
+ hdev->stat.byte_tx += len;
+
+ skb_pull(skb, len);
+ if (skb->len) {
+ hu->tx_skb = skb;
+ break;
+ }
+
+ hci_uart_tx_complete(hu, hci_skb_pkt_type(skb));
+ kfree_skb(skb);
+ }
+ } while(test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state));
+
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+}
+
+/* ------- Interface to HCI layer ------ */
+
+/* Initialize device */
+static int hci_uart_open(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
+ BT_DBG("%s %p", hdev->name, hdev);
+
+ serdev_device_set_client_ops(hu->serdev, &hci_serdev_client_ops);
+
+ return serdev_device_open(hu->serdev);
+}
+
+/* Reset device */
+static int hci_uart_flush(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
+ BT_DBG("hdev %p serdev %p", hdev, hu->serdev);
+
+ if (hu->tx_skb) {
+ kfree_skb(hu->tx_skb); hu->tx_skb = NULL;
+ }
+
+ /* Flush any pending characters in the driver and discipline. */
+ serdev_device_write_flush(hu->serdev);
+
+ if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
+ hu->proto->flush(hu);
+
+ return 0;
+}
+
+/* Close device */
+static int hci_uart_close(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
+ BT_DBG("hdev %p", hdev);
+
+ hci_uart_flush(hdev);
+ hdev->flush = NULL;
+
+ serdev_device_close(hu->serdev);
+
+ return 0;
+}
+
+/* Send frames from HCI layer */
+static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+
+ BT_DBG("%s: type %d len %d", hdev->name, hci_skb_pkt_type(skb),
+ skb->len);
+
+ hu->proto->enqueue(hu, skb);
+
+ hci_uart_tx_wakeup(hu);
+
+ return 0;
+}
+
+static int hci_uart_setup(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct hci_rp_read_local_version *ver;
+ struct sk_buff *skb;
+ unsigned int speed;
+ int err;
+
+ /* Init speed if any */
+ if (hu->init_speed)
+ speed = hu->init_speed;
+ else if (hu->proto->init_speed)
+ speed = hu->proto->init_speed;
+ else
+ speed = 0;
+
+ if (speed)
+ serdev_device_set_baudrate(hu->serdev, speed);
+
+ /* Operational speed if any */
+ if (hu->oper_speed)
+ speed = hu->oper_speed;
+ else if (hu->proto->oper_speed)
+ speed = hu->proto->oper_speed;
+ else
+ speed = 0;
+
+ if (hu->proto->set_baudrate && speed) {
+ err = hu->proto->set_baudrate(hu, speed);
+ if (err)
+ BT_ERR("%s: failed to set baudrate", hdev->name);
+ else
+ serdev_device_set_baudrate(hu->serdev, speed);
+ }
+
+ if (hu->proto->setup)
+ return hu->proto->setup(hu);
+
+ if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags))
+ return 0;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reading local version information failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return 0;
+ }
+
+ if (skb->len != sizeof(*ver)) {
+ BT_ERR("%s: Event length mismatch for version information",
+ hdev->name);
+ }
+
+ kfree_skb(skb);
+ return 0;
+}
+
+/** hci_uart_write_wakeup - transmit buffer wakeup
+ * @serdev: serial device
+ *
+ * This function is called by the serdev framework when it accepts
+ * more data being sent.
+ */
+static void hci_uart_write_wakeup(struct serdev_device *serdev)
+{
+ struct hci_uart *hu = serdev_device_get_drvdata(serdev);
+
+ BT_DBG("");
+
+ if (!hu || serdev != hu->serdev) {
+ WARN_ON(1);
+ return;
+ }
+
+ if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
+ hci_uart_tx_wakeup(hu);
+}
+
+/** hci_uart_receive_buf - receive buffer wakeup
+ * @serdev: serial device
+ * @data: pointer to received data
+ * @count: count of received data in bytes
+ *
+ * This function is called by the serdev framework when it received data
+ * in the RX buffer.
+ *
+ * Return: number of processed bytes
+ */
+static int hci_uart_receive_buf(struct serdev_device *serdev, const u8 *data,
+ size_t count)
+{
+ struct hci_uart *hu = serdev_device_get_drvdata(serdev);
+
+ if (!hu || serdev != hu->serdev) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ if (!test_bit(HCI_UART_PROTO_READY, &hu->flags))
+ return 0;
+
+ /* It does not need a lock here as it is already protected by a mutex in
+ * tty caller
+ */
+ hu->proto->recv(hu, data, count);
+
+ if (hu->hdev)
+ hu->hdev->stat.byte_rx += count;
+
+ return count;
+}
+
+struct serdev_device_ops hci_serdev_client_ops = {
+ .receive_buf = hci_uart_receive_buf,
+ .write_wakeup = hci_uart_write_wakeup,
+};
+
+int hci_uart_register_device(struct hci_uart *hu,
+ const struct hci_uart_proto *p)
+{
+ int err;
+ struct hci_dev *hdev;
+
+ BT_DBG("");
+
+ err = p->open(hu);
+ if (err)
+ return err;
+
+ hu->proto = p;
+ set_bit(HCI_UART_PROTO_READY, &hu->flags);
+
+ /* Initialize and register HCI device */
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ BT_ERR("Can't allocate HCI device");
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+
+ hu->hdev = hdev;
+
+ hdev->bus = HCI_UART;
+ hci_set_drvdata(hdev, hu);
+
+ INIT_WORK(&hu->write_work, hci_uart_write_work);
+
+ /* Only when vendor specific setup callback is provided, consider
+ * the manufacturer information valid. This avoids filling in the
+ * value for Ericsson when nothing is specified.
+ */
+ if (hu->proto->setup)
+ hdev->manufacturer = hu->proto->manufacturer;
+
+ hdev->open = hci_uart_open;
+ hdev->close = hci_uart_close;
+ hdev->flush = hci_uart_flush;
+ hdev->send = hci_uart_send_frame;
+ hdev->setup = hci_uart_setup;
+ SET_HCIDEV_DEV(hdev, &hu->serdev->dev);
+
+ if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
+ set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
+
+ if (test_bit(HCI_UART_EXT_CONFIG, &hu->hdev_flags))
+ set_bit(HCI_QUIRK_EXTERNAL_CONFIG, &hdev->quirks);
+
+ if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
+ set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+ if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
+ hdev->dev_type = HCI_AMP;
+ else
+ hdev->dev_type = HCI_PRIMARY;
+
+ if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
+ return 0;
+
+ if (hci_register_dev(hdev) < 0) {
+ BT_ERR("Can't register HCI device");
+ err = -ENODEV;
+ goto err_register;
+ }
+
+ set_bit(HCI_UART_REGISTERED, &hu->flags);
+
+ return 0;
+
+err_register:
+ hci_free_dev(hdev);
+err_alloc:
+ clear_bit(HCI_UART_PROTO_READY, &hu->flags);
+ p->close(hu);
+ return err;
+}
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 4aff50960cac..1b41c661bbb8 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -58,6 +58,7 @@
#define HCI_UART_VND_DETECT 5
struct hci_uart;
+struct serdev_device;
struct hci_uart_proto {
unsigned int id;
@@ -77,6 +78,7 @@ struct hci_uart_proto {
struct hci_uart {
struct tty_struct *tty;
+ struct serdev_device *serdev;
struct hci_dev *hdev;
unsigned long flags;
unsigned long hdev_flags;
@@ -108,6 +110,8 @@ struct hci_uart {
int hci_uart_register_proto(const struct hci_uart_proto *p);
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
+int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p);
+
int hci_uart_tx_wakeup(struct hci_uart *hu);
int hci_uart_init_ready(struct hci_uart *hu);
void hci_uart_init_tty(struct hci_uart *hu);
--
2.11.0
^ permalink raw reply related
* [PATCHv3 05/10] Bluetooth: hci_uart: add support for word alignment
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
This will be used by Nokia's H4+ protocol, which
uses 2-byte aligned packets.
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv1:
* use u8 instead of uint8_t
---
drivers/bluetooth/hci_h4.c | 17 +++++++++++++++++
drivers/bluetooth/hci_ldisc.c | 4 ++++
drivers/bluetooth/hci_uart.h | 3 +++
3 files changed, 24 insertions(+)
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 635597b6e168..82e5a32b87a4 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -171,9 +171,20 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
const unsigned char *buffer, int count,
const struct h4_recv_pkt *pkts, int pkts_count)
{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ u8 alignment = hu->alignment;
+
while (count) {
int i, len;
+ /* remove padding bytes from buffer */
+ for (; hu->padding && count > 0; hu->padding--) {
+ count--;
+ buffer++;
+ }
+ if (!count)
+ break;
+
if (!skb) {
for (i = 0; i < pkts_count; i++) {
if (buffer[0] != (&pkts[i])->type)
@@ -253,11 +264,17 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
}
if (!dlen) {
+ hu->padding = (skb->len - 1) % alignment;
+ hu->padding = (alignment - hu->padding) % alignment;
+
/* No more data, complete frame */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
}
} else {
+ hu->padding = (skb->len - 1) % alignment;
+ hu->padding = (alignment - hu->padding) % alignment;
+
/* Complete frame */
(&pkts[i])->recv(hdev, skb);
skb = NULL;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 9497c469efd2..0ec8a94bd712 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -459,6 +459,10 @@ static int hci_uart_tty_open(struct tty_struct *tty)
hu->tty = tty;
tty->receive_room = 65536;
+ /* disable alignment support by default */
+ hu->alignment = 1;
+ hu->padding = 0;
+
INIT_WORK(&hu->init_ready, hci_uart_init_work);
INIT_WORK(&hu->write_work, hci_uart_write_work);
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 070139513e65..4aff50960cac 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -92,6 +92,9 @@ struct hci_uart {
unsigned int init_speed;
unsigned int oper_speed;
+
+ u8 alignment;
+ u8 padding;
};
/* HCI_UART proto flag bits */
--
2.11.0
^ permalink raw reply related
* [PATCHv3 04/10] serdev: add helpers for cts and rts handling
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
Add serdev helper functions for handling of cts and rts
lines using the serdev's tiocm functions.
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv2:
* use time_is_after_jiffies(xyz) instead of !time_after(jiffies, xyz)
* drop OUT2 handling in rts function
---
include/linux/serdev.h | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index e29a270f603c..37395b8eb8f1 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -16,6 +16,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/termios.h>
+#include <linux/delay.h>
struct serdev_controller;
struct serdev_device;
@@ -254,6 +255,36 @@ static inline int serdev_device_write_room(struct serdev_device *sdev)
#endif /* CONFIG_SERIAL_DEV_BUS */
+static inline bool serdev_device_get_cts(struct serdev_device *serdev)
+{
+ int status = serdev_device_get_tiocm(serdev);
+ return !!(status & TIOCM_CTS);
+}
+
+static inline int serdev_device_wait_for_cts(struct serdev_device *serdev, bool state, int timeout_ms)
+{
+ unsigned long timeout;
+ bool signal;
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ while (time_is_after_jiffies(timeout)) {
+ signal = serdev_device_get_cts(serdev);
+ if (signal == state)
+ return 0;
+ usleep_range(1000, 2000);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static inline int serdev_device_set_rts(struct serdev_device *serdev, bool enable)
+{
+ if (enable)
+ return serdev_device_set_tiocm(serdev, TIOCM_RTS, 0);
+ else
+ return serdev_device_set_tiocm(serdev, 0, TIOCM_RTS);
+}
+
/*
* serdev hooks into TTY core
*/
--
2.11.0
^ permalink raw reply related
* [PATCHv3 03/10] serdev: implement get/set tiocm
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
Add method for getting and setting tiocm.
Acked-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/tty/serdev/core.c | 22 ++++++++++++++++++++++
drivers/tty/serdev/serdev-ttyport.c | 24 ++++++++++++++++++++++++
include/linux/serdev.h | 13 +++++++++++++
3 files changed, 59 insertions(+)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index a63b74031e22..1e1cbae3a0ea 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -184,6 +184,28 @@ void serdev_device_wait_until_sent(struct serdev_device *serdev, long timeout)
}
EXPORT_SYMBOL_GPL(serdev_device_wait_until_sent);
+int serdev_device_get_tiocm(struct serdev_device *serdev)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->get_tiocm)
+ return -ENOTSUPP;
+
+ return ctrl->ops->get_tiocm(ctrl);
+}
+EXPORT_SYMBOL_GPL(serdev_device_get_tiocm);
+
+int serdev_device_set_tiocm(struct serdev_device *serdev, int set, int clear)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->set_tiocm)
+ return -ENOTSUPP;
+
+ return ctrl->ops->set_tiocm(ctrl, set, clear);
+}
+EXPORT_SYMBOL_GPL(serdev_device_set_tiocm);
+
static int serdev_drv_probe(struct device *dev)
{
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index 50dc75c4d204..487c88f6aa0e 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -176,6 +176,28 @@ static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout
tty_wait_until_sent(tty, timeout);
}
+static int ttyport_get_tiocm(struct serdev_controller *ctrl)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+
+ if (!tty->ops->tiocmget)
+ return -ENOTSUPP;
+
+ return tty->driver->ops->tiocmget(tty);
+}
+
+static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+
+ if (!tty->ops->tiocmset)
+ return -ENOTSUPP;
+
+ return tty->driver->ops->tiocmset(tty, set, clear);
+}
+
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
@@ -185,6 +207,8 @@ static const struct serdev_controller_ops ctrl_ops = {
.set_flow_control = ttyport_set_flow_control,
.set_baudrate = ttyport_set_baudrate,
.wait_until_sent = ttyport_wait_until_sent,
+ .get_tiocm = ttyport_get_tiocm,
+ .set_tiocm = ttyport_set_tiocm,
};
struct device *serdev_tty_port_register(struct tty_port *port,
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index a308b206d204..e29a270f603c 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -15,6 +15,7 @@
#include <linux/types.h>
#include <linux/device.h>
+#include <linux/termios.h>
struct serdev_controller;
struct serdev_device;
@@ -82,6 +83,8 @@ struct serdev_controller_ops {
void (*set_flow_control)(struct serdev_controller *, bool);
unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int);
void (*wait_until_sent)(struct serdev_controller *, long);
+ int (*get_tiocm)(struct serdev_controller *);
+ int (*set_tiocm)(struct serdev_controller *, unsigned int, unsigned int);
};
/**
@@ -188,6 +191,8 @@ void serdev_device_close(struct serdev_device *);
unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
void serdev_device_set_flow_control(struct serdev_device *, bool);
void serdev_device_wait_until_sent(struct serdev_device *, long);
+int serdev_device_get_tiocm(struct serdev_device *);
+int serdev_device_set_tiocm(struct serdev_device *, int, int);
int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
void serdev_device_write_flush(struct serdev_device *);
int serdev_device_write_room(struct serdev_device *);
@@ -226,6 +231,14 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev
}
static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {}
static inline void serdev_device_wait_until_sent(struct serdev_device *sdev, long timeout) {}
+static inline int serdev_device_get_tiocm(struct serdev_device *serdev)
+{
+ return -ENOTSUPP;
+}
+static inline int serdev_device_set_tiocm(struct serdev_device *serdev, int set, int clear)
+{
+ return -ENOTSUPP;
+}
static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsigned char *buf, size_t count)
{
return -ENODEV;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 02/10] serdev: add serdev_device_wait_until_sent
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
Add method, which waits until the transmission buffer has been sent.
Note, that the change in ttyport_write_wakeup is related, since
tty_wait_until_sent will hang without that change.
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Changes since PATCHv2:
* Avoid goto in ttyport_write_wakeup
---
drivers/tty/serdev/core.c | 11 +++++++++++
drivers/tty/serdev/serdev-ttyport.c | 18 ++++++++++++++----
include/linux/serdev.h | 3 +++
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
index f4c6c90add78..a63b74031e22 100644
--- a/drivers/tty/serdev/core.c
+++ b/drivers/tty/serdev/core.c
@@ -173,6 +173,17 @@ void serdev_device_set_flow_control(struct serdev_device *serdev, bool enable)
}
EXPORT_SYMBOL_GPL(serdev_device_set_flow_control);
+void serdev_device_wait_until_sent(struct serdev_device *serdev, long timeout)
+{
+ struct serdev_controller *ctrl = serdev->ctrl;
+
+ if (!ctrl || !ctrl->ops->wait_until_sent)
+ return;
+
+ ctrl->ops->wait_until_sent(ctrl, timeout);
+}
+EXPORT_SYMBOL_GPL(serdev_device_wait_until_sent);
+
static int serdev_drv_probe(struct device *dev)
{
const struct serdev_device_driver *sdrv = to_serdev_device_driver(dev->driver);
diff --git a/drivers/tty/serdev/serdev-ttyport.c b/drivers/tty/serdev/serdev-ttyport.c
index d05393594f15..50dc75c4d204 100644
--- a/drivers/tty/serdev/serdev-ttyport.c
+++ b/drivers/tty/serdev/serdev-ttyport.c
@@ -14,6 +14,7 @@
#include <linux/serdev.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
+#include <linux/poll.h>
#define SERPORT_ACTIVE 1
@@ -46,11 +47,11 @@ static void ttyport_write_wakeup(struct tty_port *port)
struct serdev_controller *ctrl = port->client_data;
struct serport *serport = serdev_controller_get_drvdata(ctrl);
- if (!test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags))
- return;
-
- if (test_bit(SERPORT_ACTIVE, &serport->flags))
+ if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) &&
+ test_bit(SERPORT_ACTIVE, &serport->flags))
serdev_controller_write_wakeup(ctrl);
+
+ wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT);
}
static const struct tty_port_client_operations client_ops = {
@@ -167,6 +168,14 @@ static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable
tty_set_termios(tty, &ktermios);
}
+static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout)
+{
+ struct serport *serport = serdev_controller_get_drvdata(ctrl);
+ struct tty_struct *tty = serport->tty;
+
+ tty_wait_until_sent(tty, timeout);
+}
+
static const struct serdev_controller_ops ctrl_ops = {
.write_buf = ttyport_write_buf,
.write_flush = ttyport_write_flush,
@@ -175,6 +184,7 @@ static const struct serdev_controller_ops ctrl_ops = {
.close = ttyport_close,
.set_flow_control = ttyport_set_flow_control,
.set_baudrate = ttyport_set_baudrate,
+ .wait_until_sent = ttyport_wait_until_sent,
};
struct device *serdev_tty_port_register(struct tty_port *port,
diff --git a/include/linux/serdev.h b/include/linux/serdev.h
index 9519da6253a8..a308b206d204 100644
--- a/include/linux/serdev.h
+++ b/include/linux/serdev.h
@@ -81,6 +81,7 @@ struct serdev_controller_ops {
void (*close)(struct serdev_controller *);
void (*set_flow_control)(struct serdev_controller *, bool);
unsigned int (*set_baudrate)(struct serdev_controller *, unsigned int);
+ void (*wait_until_sent)(struct serdev_controller *, long);
};
/**
@@ -186,6 +187,7 @@ int serdev_device_open(struct serdev_device *);
void serdev_device_close(struct serdev_device *);
unsigned int serdev_device_set_baudrate(struct serdev_device *, unsigned int);
void serdev_device_set_flow_control(struct serdev_device *, bool);
+void serdev_device_wait_until_sent(struct serdev_device *, long);
int serdev_device_write_buf(struct serdev_device *, const unsigned char *, size_t);
void serdev_device_write_flush(struct serdev_device *);
int serdev_device_write_room(struct serdev_device *);
@@ -223,6 +225,7 @@ static inline unsigned int serdev_device_set_baudrate(struct serdev_device *sdev
return 0;
}
static inline void serdev_device_set_flow_control(struct serdev_device *sdev, bool enable) {}
+static inline void serdev_device_wait_until_sent(struct serdev_device *sdev, long timeout) {}
static inline int serdev_device_write_buf(struct serdev_device *sdev, const unsigned char *buf, size_t count)
{
return -ENODEV;
--
2.11.0
^ permalink raw reply related
* [PATCHv3 01/10] tty: serial: omap: add UPF_BOOT_AUTOCONF flag for DT init
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
In-Reply-To: <20170328155939.31566-1-sre@kernel.org>
The UPF_BOOT_AUTOCONF flag is needed for proper
flow control support.
Acked-by: Pavel Machek <pavel@ucw.cz>
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
Hi,
This patch can be queued independently - there is no compile time dependency
regarding nokia-bluetooth. Also 8250_omap.c can be used with nokia-bluetooth
(I use this driver nowadays), which does flow control right already.
-- Sebastian
---
drivers/tty/serial/omap-serial.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 6c6f82ad8d5c..a4734649a0f0 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -1597,6 +1597,9 @@ static struct omap_uart_port_info *of_get_uart_port_info(struct device *dev)
of_property_read_u32(dev->of_node, "clock-frequency",
&omap_up_info->uartclk);
+
+ omap_up_info->flags = UPF_BOOT_AUTOCONF;
+
return omap_up_info;
}
--
2.11.0
^ permalink raw reply related
* [PATCHv3 00/10] Nokia H4+ support
From: Sebastian Reichel @ 2017-03-28 15:59 UTC (permalink / raw)
To: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
Johan Hedberg, Rob Herring
Cc: Samuel Thibault, Pavel Machek, Tony Lindgren, Greg Kroah-Hartman,
Jiri Slaby, Mark Rutland, linux-bluetooth, linux-serial,
devicetree, linux-kernel
Hi,
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.
The patchset is based upon 4.11-rc1 and is also available from the following
branch:
https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-n900.git/log/?h=nokia-bt-serdev-v3
-- Sebastian
Rob Herring (1):
Bluetooth: hci_uart: add serdev driver support library
Sebastian Reichel (9):
tty: serial: omap: add UPF_BOOT_AUTOCONF flag for DT init
serdev: add serdev_device_wait_until_sent
serdev: implement get/set tiocm
serdev: add helpers for cts and rts handling
Bluetooth: hci_uart: add support for word alignment
Bluetooth: hci_serdev: do not open device in hci open
Bluetooth: hci_serdev: allow modular drivers
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 | 3 +
drivers/bluetooth/hci_h4.c | 17 +
drivers/bluetooth/hci_ldisc.c | 5 +
drivers/bluetooth/hci_nokia.c | 819 +++++++++++++++++++++
drivers/bluetooth/hci_serdev.c | 356 +++++++++
drivers/bluetooth/hci_uart.h | 7 +
drivers/tty/serdev/core.c | 33 +
drivers/tty/serdev/serdev-ttyport.c | 42 +-
drivers/tty/serial/omap-serial.c | 3 +
include/linux/serdev.h | 47 ++
12 files changed, 1391 insertions(+), 4 deletions(-)
create mode 100644 Documentation/devicetree/bindings/net/nokia-bluetooth.txt
create mode 100644 drivers/bluetooth/hci_nokia.c
create mode 100644 drivers/bluetooth/hci_serdev.c
--
2.11.0
^ permalink raw reply
* Re: [PATCH] 6lowpan: set peer_addr correctly again
From: Von Dentz, Luiz @ 2017-03-28 13:42 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Arnd Bergmann, Gustavo F. Padovan, Johan Hedberg, David S. Miller,
Stefan Schmidt, Jukka Rissanen, Eric Dumazet, Patrik Flykt,
Alexander Aring, Glenn Ruben Bakke,
linux-bluetooth@vger.kernel.org, netdev, linux-kernel
In-Reply-To: <368A8A18-0B9B-4733-86EF-D44C8E9CAE36@holtmann.org>
Hi Marcel,
On Tue, Mar 28, 2017 at 4:37 PM, Marcel Holtmann <marcel@holtmann.org> wrot=
e:
> Hi Arnd,
>
>> A bugfix accidentally changed one line to return the peer_addr
>> from setup_header, causing it to become unused:
>>
>> net/bluetooth/6lowpan.c: In function 'setup_header':
>> net/bluetooth/6lowpan.c:402:14: error: parameter 'peer_addr' set but not=
used [-Werror=3Dunused-but-set-parameter]
>>
>> The only user of the variable is a subsequent printk(), and
>> it is not otherwise initialized, so reverting the changed line
>> looks like the right fix.
>>
>> Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
>> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
>> ---
>> net/bluetooth/6lowpan.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> I took Colin=E2=80=99s patch since it showed up first in my inbox.
Thanks, I might be missing something since the error doesn't show up for me=
:
CC [M] net/bluetooth/6lowpan.o
LD [M] net/bluetooth/bluetooth_6lowpan.o
^ permalink raw reply
* Re: [PATCH] 6lowpan: set peer_addr correctly again
From: Marcel Holtmann @ 2017-03-28 13:37 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Gustavo F. Padovan, Johan Hedberg, David S. Miller,
Stefan Schmidt, Jukka Rissanen, Luiz Augusto von Dentz,
Eric Dumazet, Patrik Flykt, Alexander Aring, Glenn Ruben Bakke,
linux-bluetooth, netdev, linux-kernel
In-Reply-To: <20170328132935.382216-1-arnd@arndb.de>
Hi Arnd,
> A bugfix accidentally changed one line to return the peer_addr
> from setup_header, causing it to become unused:
>
> net/bluetooth/6lowpan.c: In function 'setup_header':
> net/bluetooth/6lowpan.c:402:14: error: parameter 'peer_addr' set but not used [-Werror=unused-but-set-parameter]
>
> The only user of the variable is a subsequent printk(), and
> it is not otherwise initialized, so reverting the changed line
> looks like the right fix.
>
> Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> net/bluetooth/6lowpan.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
I took Colin’s patch since it showed up first in my inbox.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] 6lowpan: fix assignment of peer_addr
From: Marcel Holtmann @ 2017-03-28 13:36 UTC (permalink / raw)
To: Colin King
Cc: Gustavo F. Padovan, Johan Hedberg, David S. Miller,
Bluez mailing list, netdev, kernel-janitors, linux-kernel
In-Reply-To: <20170328121129.18421-1-colin.king@canonical.com>
Hi Colin,
> The data from peer->chan->dst is not being copied to peer_addr, the
> current code just updates the pointer and not the contents of what
> it points to. Fix this with the intended assignment.
>
> Detected by CoverityScan, CID#1422111 ("Parse warning
> (PW.PARAM_SET_BUT_NOT_USED)")
>
> Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
> net/bluetooth/6lowpan.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH BlueZ] tools: Fix the sock handle leak
From: Luiz Augusto von Dentz @ 2017-03-28 13:35 UTC (permalink / raw)
To: Lee Hyuk; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1490663534-30177-1-git-send-email-hyuk0512.lee@samsung.com>
Hi,
On Tue, Mar 28, 2017 at 4:12 AM, <hyuk0512.lee@samsung.com> wrote:
> From: Lee Hyuk <hyuk0512.lee@samsung.com>
>
> This patch adds function "close" for fixing the socket handle leak.
> ---
> tools/rfcomm.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/tools/rfcomm.c b/tools/rfcomm.c
> index 809c240..03359be 100644
> --- a/tools/rfcomm.c
> +++ b/tools/rfcomm.c
> @@ -310,6 +310,7 @@ static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **arg
>
> if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
> perror("Can't set linger option");
> + close(sk);
> return;
> }
> }
> --
> 1.9.1
I can probably guess where this is coming from, a static analyzer,
well guess what if the process exits right away all the fd opened are
closed so this is most likely useless.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] 6lowpan: fix assignment of peer_addr
From: Luiz Augusto von Dentz @ 2017-03-28 13:32 UTC (permalink / raw)
To: Colin King
Cc: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, David S . Miller,
linux-bluetooth@vger.kernel.org, open list:NETWORKING [GENERAL],
kernel-janitors, Linux Kernel Mailing List
In-Reply-To: <20170328121129.18421-1-colin.king@canonical.com>
Hi Colin,
On Tue, Mar 28, 2017 at 3:11 PM, Colin King <colin.king@canonical.com> wrote:
> From: Colin Ian King <colin.king@canonical.com>
>
> The data from peer->chan->dst is not being copied to peer_addr, the
> current code just updates the pointer and not the contents of what
> it points to. Fix this with the intended assignment.
>
> Detected by CoverityScan, CID#1422111 ("Parse warning
> (PW.PARAM_SET_BUT_NOT_USED)")
>
> Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
> Signed-off-by: Colin Ian King <colin.king@canonical.com>
> ---
> net/bluetooth/6lowpan.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 24348c8579dd..ba28c7b1557f 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -432,7 +432,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
> }
>
> daddr = peer->lladdr;
> - peer_addr = &peer->chan->dst;
> + *peer_addr = peer->chan->dst;
> *peer_addr_type = peer->chan->dst_type;
> lowpan_cb(skb)->chan = peer->chan;
>
> --
> 2.11.0
Reviewed-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH] 6lowpan: set peer_addr correctly again
From: Arnd Bergmann @ 2017-03-28 13:29 UTC (permalink / raw)
To: Marcel Holtmann, Gustavo Padovan, Johan Hedberg
Cc: Arnd Bergmann, David S. Miller, Stefan Schmidt, Jukka Rissanen,
Luiz Augusto von Dentz, Eric Dumazet, Patrik Flykt,
Alexander Aring, Glenn Ruben Bakke, linux-bluetooth, netdev,
linux-kernel
A bugfix accidentally changed one line to return the peer_addr
from setup_header, causing it to become unused:
net/bluetooth/6lowpan.c: In function 'setup_header':
net/bluetooth/6lowpan.c:402:14: error: parameter 'peer_addr' set but not used [-Werror=unused-but-set-parameter]
The only user of the variable is a subsequent printk(), and
it is not otherwise initialized, so reverting the changed line
looks like the right fix.
Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
net/bluetooth/6lowpan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 24348c8579dd..ba28c7b1557f 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -432,7 +432,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
}
daddr = peer->lladdr;
- peer_addr = &peer->chan->dst;
+ *peer_addr = peer->chan->dst;
*peer_addr_type = peer->chan->dst_type;
lowpan_cb(skb)->chan = peer->chan;
--
2.9.0
^ permalink raw reply related
* [PATCH] 6lowpan: fix assignment of peer_addr
From: Colin King @ 2017-03-28 12:11 UTC (permalink / raw)
To: Marcel Holtmann, Gustavo Padovan, Johan Hedberg, David S . Miller,
linux-bluetooth, netdev
Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
The data from peer->chan->dst is not being copied to peer_addr, the
current code just updates the pointer and not the contents of what
it points to. Fix this with the intended assignment.
Detected by CoverityScan, CID#1422111 ("Parse warning
(PW.PARAM_SET_BUT_NOT_USED)")
Fixes: fb6f2f606ce8 ("6lowpan: Fix IID format for Bluetooth")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
net/bluetooth/6lowpan.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 24348c8579dd..ba28c7b1557f 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -432,7 +432,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
}
daddr = peer->lladdr;
- peer_addr = &peer->chan->dst;
+ *peer_addr = peer->chan->dst;
*peer_addr_type = peer->chan->dst_type;
lowpan_cb(skb)->chan = peer->chan;
--
2.11.0
^ 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