* [PATCH 4/8] Bluetooth: Use IS_ERR_OR_NULL for checking bt_debugfs
From: Marcel Holtmann @ 2013-10-18 0:24 UTC (permalink / raw)
To: linux-bluetooth
Make sure to use IS_ERR_OR_NULL for checking the existing of the root
debugfs dentry bt_debugfs.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap_core.c | 11 +++++------
net/bluetooth/rfcomm/core.c | 14 +++++++-------
net/bluetooth/rfcomm/sock.c | 14 +++++++-------
net/bluetooth/sco.c | 13 ++++++-------
4 files changed, 25 insertions(+), 27 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8af34d2..763b741 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -6833,12 +6833,11 @@ int __init l2cap_init(void)
if (err < 0)
return err;
- if (bt_debugfs) {
- l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
- NULL, &l2cap_debugfs_fops);
- if (!l2cap_debugfs)
- BT_ERR("Failed to create L2CAP debug file");
- }
+ if (IS_ERR_OR_NULL(bt_debugfs))
+ return 0;
+
+ l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
+ NULL, &l2cap_debugfs_fops);
return 0;
}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 27e936a..94d06cb 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2154,13 +2154,6 @@ static int __init rfcomm_init(void)
goto unregister;
}
- if (bt_debugfs) {
- rfcomm_dlc_debugfs = debugfs_create_file("rfcomm_dlc", 0444,
- bt_debugfs, NULL, &rfcomm_dlc_debugfs_fops);
- if (!rfcomm_dlc_debugfs)
- BT_ERR("Failed to create RFCOMM debug file");
- }
-
err = rfcomm_init_ttys();
if (err < 0)
goto stop;
@@ -2171,6 +2164,13 @@ static int __init rfcomm_init(void)
BT_INFO("RFCOMM ver %s", VERSION);
+ if (IS_ERR_OR_NULL(bt_debugfs))
+ return 0;
+
+ rfcomm_dlc_debugfs = debugfs_create_file("rfcomm_dlc", 0444,
+ bt_debugfs, NULL,
+ &rfcomm_dlc_debugfs_fops);
+
return 0;
cleanup:
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index df17276..c4d3d42 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -1051,15 +1051,15 @@ int __init rfcomm_init_sockets(void)
goto error;
}
- if (bt_debugfs) {
- rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
- bt_debugfs, NULL, &rfcomm_sock_debugfs_fops);
- if (!rfcomm_sock_debugfs)
- BT_ERR("Failed to create RFCOMM debug file");
- }
-
BT_INFO("RFCOMM socket layer initialized");
+ if (IS_ERR_OR_NULL(bt_debugfs))
+ return 0;
+
+ rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
+ bt_debugfs, NULL,
+ &rfcomm_sock_debugfs_fops);
+
return 0;
error:
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index a92aeba..12a0e51 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -1177,15 +1177,14 @@ int __init sco_init(void)
goto error;
}
- if (bt_debugfs) {
- sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
- NULL, &sco_debugfs_fops);
- if (!sco_debugfs)
- BT_ERR("Failed to create SCO debug file");
- }
-
BT_INFO("SCO socket layer initialized");
+ if (IS_ERR_OR_NULL(bt_debugfs))
+ return 0;
+
+ sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
+ NULL, &sco_debugfs_fops);
+
return 0;
error:
--
1.8.3.1
^ permalink raw reply related
* [PATCH 5/8] Bluetooth: Create HCI device debugfs directory in hci_register_dev
From: Marcel Holtmann @ 2013-10-18 0:24 UTC (permalink / raw)
To: linux-bluetooth
Create the debugfs directory for each HCI device directly in
hci_register_dev function and remove it during hci_unregister_dev.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_core.c | 5 +++++
net/bluetooth/hci_sysfs.c | 16 +---------------
2 files changed, 6 insertions(+), 15 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 0fb9f6d..f7ba818 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2479,6 +2479,9 @@ int hci_register_dev(struct hci_dev *hdev)
goto err;
}
+ if (!IS_ERR_OR_NULL(bt_debugfs))
+ hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
+
error = hci_add_sysfs(hdev);
if (error < 0)
goto err_wqueue;
@@ -2569,6 +2572,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_del_sysfs(hdev);
+ debugfs_remove_recursive(hdev->debugfs);
+
destroy_workqueue(hdev->workqueue);
destroy_workqueue(hdev->req_workqueue);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 077037e..0e71318 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -409,32 +409,18 @@ void hci_init_sysfs(struct hci_dev *hdev)
int hci_add_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
- int err;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
dev_set_name(dev, "%s", hdev->name);
- err = device_add(dev);
- if (err < 0)
- return err;
-
- if (!bt_debugfs)
- return 0;
-
- hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
- if (!hdev->debugfs)
- return 0;
-
- return 0;
+ return device_add(dev);
}
void hci_del_sysfs(struct hci_dev *hdev)
{
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
- debugfs_remove_recursive(hdev->debugfs);
-
device_del(&hdev->dev);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH 6/8] Bluetooth: Create root debugfs directory during module init
From: Marcel Holtmann @ 2013-10-18 0:24 UTC (permalink / raw)
To: linux-bluetooth
Create the root Bluetooth debugfs directory during module init
and remove it on module exit.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/af_bluetooth.c | 9 ++++++++-
net/bluetooth/hci_sysfs.c | 8 --------
2 files changed, 8 insertions(+), 9 deletions(-)
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 1f1a111..f6a1671 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -25,6 +25,7 @@
/* Bluetooth address family and sockets. */
#include <linux/module.h>
+#include <linux/debugfs.h>
#include <asm/ioctls.h>
#include <net/bluetooth/bluetooth.h>
@@ -708,12 +709,17 @@ static struct net_proto_family bt_sock_family_ops = {
.create = bt_sock_create,
};
+struct dentry *bt_debugfs;
+EXPORT_SYMBOL_GPL(bt_debugfs);
+
static int __init bt_init(void)
{
int err;
BT_INFO("Core ver %s", VERSION);
+ bt_debugfs = debugfs_create_dir("bluetooth", NULL);
+
err = bt_sysfs_init();
if (err < 0)
return err;
@@ -754,7 +760,6 @@ error:
static void __exit bt_exit(void)
{
-
sco_exit();
l2cap_exit();
@@ -764,6 +769,8 @@ static void __exit bt_exit(void)
sock_unregister(PF_BLUETOOTH);
bt_sysfs_cleanup();
+
+ debugfs_remove_recursive(bt_debugfs);
}
subsys_initcall(bt_init);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 0e71318..320a761 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -1,6 +1,5 @@
/* Bluetooth HCI driver model support. */
-#include <linux/debugfs.h>
#include <linux/module.h>
#include <net/bluetooth/bluetooth.h>
@@ -8,9 +7,6 @@
static struct class *bt_class;
-struct dentry *bt_debugfs;
-EXPORT_SYMBOL_GPL(bt_debugfs);
-
static inline char *link_typetostr(int type)
{
switch (type) {
@@ -426,8 +422,6 @@ void hci_del_sysfs(struct hci_dev *hdev)
int __init bt_sysfs_init(void)
{
- bt_debugfs = debugfs_create_dir("bluetooth", NULL);
-
bt_class = class_create(THIS_MODULE, "bluetooth");
return PTR_ERR_OR_ZERO(bt_class);
@@ -436,6 +430,4 @@ int __init bt_sysfs_init(void)
void bt_sysfs_cleanup(void)
{
class_destroy(bt_class);
-
- debugfs_remove_recursive(bt_debugfs);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH 7/8] Bluetooth: Move device_add handling into hci_register_dev
From: Marcel Holtmann @ 2013-10-18 0:24 UTC (permalink / raw)
To: linux-bluetooth
The device_add handling can be done directly in hci_register_dev and
device_remove within hci_unregister_dev.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci_core.h | 2 --
net/bluetooth/hci_core.c | 6 ++++--
net/bluetooth/hci_sysfs.c | 18 ------------------
3 files changed, 4 insertions(+), 22 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index c6becda..9b5db01 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -768,8 +768,6 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
void hci_init_sysfs(struct hci_dev *hdev);
-int hci_add_sysfs(struct hci_dev *hdev);
-void hci_del_sysfs(struct hci_dev *hdev);
void hci_conn_init_sysfs(struct hci_conn *conn);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index f7ba818..940da80 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2482,7 +2482,9 @@ int hci_register_dev(struct hci_dev *hdev)
if (!IS_ERR_OR_NULL(bt_debugfs))
hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
- error = hci_add_sysfs(hdev);
+ dev_set_name(&hdev->dev, "%s", hdev->name);
+
+ error = device_add(&hdev->dev);
if (error < 0)
goto err_wqueue;
@@ -2570,7 +2572,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
rfkill_destroy(hdev->rfkill);
}
- hci_del_sysfs(hdev);
+ device_del(&hdev->dev);
debugfs_remove_recursive(hdev->debugfs);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 320a761..9cbf8fe 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -402,24 +402,6 @@ void hci_init_sysfs(struct hci_dev *hdev)
device_initialize(dev);
}
-int hci_add_sysfs(struct hci_dev *hdev)
-{
- struct device *dev = &hdev->dev;
-
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- dev_set_name(dev, "%s", hdev->name);
-
- return device_add(dev);
-}
-
-void hci_del_sysfs(struct hci_dev *hdev)
-{
- BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
-
- device_del(&hdev->dev);
-}
-
int __init bt_sysfs_init(void)
{
bt_class = class_create(THIS_MODULE, "bluetooth");
--
1.8.3.1
^ permalink raw reply related
* [PATCH 8/8] Bluetooth: Include address type in blacklist debugfs data
From: Marcel Holtmann @ 2013-10-18 0:24 UTC (permalink / raw)
To: linux-bluetooth
The address type is important for the blacklist entries. So include
it at well.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 940da80..a4047d6 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -65,7 +65,7 @@ static int blacklist_show(struct seq_file *f, void *p)
hci_dev_lock(hdev);
list_for_each_entry(b, &hdev->blacklist, list)
- seq_printf(f, "%pMR\n", &b->bdaddr);
+ seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
hci_dev_unlock(hdev);
return 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH] Bluetooth: Move idle_timeout and sniff_{min,max}_interval to hci_core.c
From: Marcel Holtmann @ 2013-10-18 2:16 UTC (permalink / raw)
To: linux-bluetooth
Move the debugfs configuration directly into hci_core.c and only expose
it when the controller actually support BR/EDR sniff power saving mode.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_core.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_sysfs.c | 91 ----------------------------------------------
2 files changed, 93 insertions(+), 91 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index a4047d6..e8058c3 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -195,6 +195,90 @@ static int auto_accept_delay_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
auto_accept_delay_set, "%llu\n");
+static int idle_timeout_set(void *data, u64 val)
+{
+ struct hci_dev *hdev = data;
+
+ if (val != 0 && (val < 500 || val > 3600000))
+ return -EINVAL;
+
+ hci_dev_lock(hdev);
+ hdev->idle_timeout= val;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int idle_timeout_get(void *data, u64 *val)
+{
+ struct hci_dev *hdev = data;
+
+ hci_dev_lock(hdev);
+ *val = hdev->idle_timeout;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(idle_timeout_fops, idle_timeout_get,
+ idle_timeout_set, "%llu\n");
+
+static int sniff_min_interval_set(void *data, u64 val)
+{
+ struct hci_dev *hdev = data;
+
+ if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
+ return -EINVAL;
+
+ hci_dev_lock(hdev);
+ hdev->sniff_min_interval= val;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int sniff_min_interval_get(void *data, u64 *val)
+{
+ struct hci_dev *hdev = data;
+
+ hci_dev_lock(hdev);
+ *val = hdev->sniff_min_interval;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sniff_min_interval_fops, sniff_min_interval_get,
+ sniff_min_interval_set, "%llu\n");
+
+static int sniff_max_interval_set(void *data, u64 val)
+{
+ struct hci_dev *hdev = data;
+
+ if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
+ return -EINVAL;
+
+ hci_dev_lock(hdev);
+ hdev->sniff_max_interval= val;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int sniff_max_interval_get(void *data, u64 *val)
+{
+ struct hci_dev *hdev = data;
+
+ hci_dev_lock(hdev);
+ *val = hdev->sniff_max_interval;
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(sniff_max_interval_fops, sniff_max_interval_get,
+ sniff_max_interval_set, "%llu\n");
+
static int static_address_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
@@ -923,6 +1007,15 @@ static int __hci_init(struct hci_dev *hdev)
debugfs_create_file("auto_accept_delay", 0644, hdev->debugfs,
hdev, &auto_accept_delay_fops);
+ if (lmp_sniff_capable(hdev)) {
+ debugfs_create_file("idle_timeout", 0644, hdev->debugfs,
+ hdev, &idle_timeout_fops);
+ debugfs_create_file("sniff_min_interval", 0644, hdev->debugfs,
+ hdev, &sniff_min_interval_fops);
+ debugfs_create_file("sniff_max_interval", 0644, hdev->debugfs,
+ hdev, &sniff_max_interval_fops);
+ }
+
if (lmp_le_capable(hdev))
debugfs_create_file("static_address", 0444, hdev->debugfs,
hdev, &static_address_fops);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 9cbf8fe..4fac57c 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -255,87 +255,6 @@ static ssize_t show_hci_revision(struct device *dev,
return sprintf(buf, "%d\n", hdev->hci_rev);
}
-static ssize_t show_idle_timeout(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->idle_timeout);
-}
-
-static ssize_t store_idle_timeout(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- unsigned int val;
- int rv;
-
- rv = kstrtouint(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val != 0 && (val < 500 || val > 3600000))
- return -EINVAL;
-
- hdev->idle_timeout = val;
-
- return count;
-}
-
-static ssize_t show_sniff_max_interval(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->sniff_max_interval);
-}
-
-static ssize_t store_sniff_max_interval(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- u16 val;
- int rv;
-
- rv = kstrtou16(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val == 0 || val % 2 || val < hdev->sniff_min_interval)
- return -EINVAL;
-
- hdev->sniff_max_interval = val;
-
- return count;
-}
-
-static ssize_t show_sniff_min_interval(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- return sprintf(buf, "%d\n", hdev->sniff_min_interval);
-}
-
-static ssize_t store_sniff_min_interval(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct hci_dev *hdev = to_hci_dev(dev);
- u16 val;
- int rv;
-
- rv = kstrtou16(buf, 0, &val);
- if (rv < 0)
- return rv;
-
- if (val == 0 || val % 2 || val > hdev->sniff_max_interval)
- return -EINVAL;
-
- hdev->sniff_min_interval = val;
-
- return count;
-}
-
static DEVICE_ATTR(bus, S_IRUGO, show_bus, NULL);
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
@@ -346,13 +265,6 @@ static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
-static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
- show_idle_timeout, store_idle_timeout);
-static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
- show_sniff_max_interval, store_sniff_max_interval);
-static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
- show_sniff_min_interval, store_sniff_min_interval);
-
static struct attribute *bt_host_attrs[] = {
&dev_attr_bus.attr,
&dev_attr_type.attr,
@@ -363,9 +275,6 @@ static struct attribute *bt_host_attrs[] = {
&dev_attr_manufacturer.attr,
&dev_attr_hci_version.attr,
&dev_attr_hci_revision.attr,
- &dev_attr_idle_timeout.attr,
- &dev_attr_sniff_max_interval.attr,
- &dev_attr_sniff_min_interval.attr,
NULL
};
--
1.8.3.1
^ permalink raw reply related
* How to contribute
From: Tim Wei @ 2013-10-18 2:36 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
I just fixed a bug in kernel. How can I contribute it?
My base version is Linux kernel 3.9.6. Should I download the latest
kernel and check whether it has been fixed?
Thank you and Best Regards,
Tim Wei
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix ATT socket backwards compatibility with user space
From: Johan Hedberg @ 2013-10-18 7:06 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <699FBB88-B7E3-4F64-92C8-54A70F1DE751@holtmann.org>
Hi Marcel,
On Fri, Oct 18, 2013, Marcel Holtmann wrote:
> > Old user space versions bind the Attribute Protocol socket to
> > BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or
> > BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the
> > socket parameters but we need to punch this hole to them to ensure that
> > old user space versions keep working.
> >
> > Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> > ---
> > net/bluetooth/l2cap_sock.c | 19 +++++++++++++++++--
> > 1 file changed, 17 insertions(+), 2 deletions(-)
> >
> > diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> > index 34e5a58..a43aead 100644
> > --- a/net/bluetooth/l2cap_sock.c
> > +++ b/net/bluetooth/l2cap_sock.c
> > @@ -159,8 +159,23 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
> > if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
> > return -EINVAL;
> >
> > - if (chan->src_type == BDADDR_BREDR && la.l2_bdaddr_type != BDADDR_BREDR)
> > - return -EINVAL;
> > + if (chan->src_type == BDADDR_BREDR &&
> > + la.l2_bdaddr_type != BDADDR_BREDR) {
> > + if (!bdaddr_type_is_le(la.l2_bdaddr_type))
> > + return -EINVAL;
>
> I do not understand this. The check for that la.l2_bdaddr_type is LE
> is done twice here.
The idea was simply to try to be forward compatible in case a fourth
address type is added, i.e. I made the assumption that
"a != BDADDR_BREDR" might not always be the same as "bdaddr_type_is_le(a)".
If you're ok with this assumption we should not just remove this extra
if-statement but also change the higher-level one to use
bdaddr_type_is_le() instead of making explicit comparisons with
BDADDR_BREDR.
> > +
> > + /* Old user space versions will try to bind the ATT
> > + * socket using BDADDR_BREDR, so we have to allow this
> > + * to pass and fix chan->src_type to the correct value.
> > + */
> > + if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
> > + return -EINVAL;
>
> I think we should also check that the src address is BDADDR_ANY. If it
> is not BDADDR_ANY, we should reject it as well. That is enough to make
> old userspace work. I do not want us to be any more flexible. Or are
> we actually bind to the right source adapter when calling connect().
The user space code is correct in this regard, so I'll add the extra
check for BDADDR_ANY.
> > + if (chan->scid != L2CAP_CID_ATT)
> > + return -EINVAL;
> > +
> > + chan->src_type = BDADDR_LE_PUBLIC;
> > + }
>
> I do not like the fact that we are just defaulting to BDADDR_LE_PUBLIC
> here. It might be fine since the old userspace only ever understood
> public addresses anyway. However I do not like it that much. And if we
> keep it this way, then a comment needs to explain that this is good
> enough.
I'll add a comment. We could in theory extend the code to also check for
information inside the hdev struct, but that would require too much
complexity for the benefit since we do not have the hdev available at
this point in the socket operations. That, considered together with the
fact that even now user space will have a hard-coded BDADDR_LE_PUBLIC is
imo reason enough to just keep this simple in the kernel.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] core: Fix missing adapter address type
From: Johan Hedberg @ 2013-10-18 7:08 UTC (permalink / raw)
To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1382014417-23930-1-git-send-email-claudio.takahasi@openbossa.org>
Hi Claudio,
On Thu, Oct 17, 2013, Claudio Takahasi wrote:
> This patch fixes an invalid argument error when connecting to LE
> devices. Bind and connect address type must match.
> ---
> src/device.c | 1 +
> 1 file changed, 1 insertion(+)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH 1/5] build: Add haltest command line tester
From: Johan Hedberg @ 2013-10-18 7:16 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth, Szymon Janc
In-Reply-To: <1382041721-19960-1-git-send-email-szymon.janc@gmail.com>
Hi Szymon,
On Thu, Oct 17, 2013, Szymon Janc wrote:
> This is intended for testing Android daemon and HAL library on Linux.
> ---
> Makefile.android | 14 ++++++++++++++
> 1 file changed, 14 insertions(+)
All five patches have been applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix ATT socket backwards compatibility with user space
From: Marcel Holtmann @ 2013-10-18 7:48 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <20131018070643.GA22824@x220.p-661hnu-f1>
Hi Johan,
>>> Old user space versions bind the Attribute Protocol socket to
>>> BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or
>>> BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the
>>> socket parameters but we need to punch this hole to them to ensure that
>>> old user space versions keep working.
>>>
>>> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
>>> ---
>>> net/bluetooth/l2cap_sock.c | 19 +++++++++++++++++--
>>> 1 file changed, 17 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
>>> index 34e5a58..a43aead 100644
>>> --- a/net/bluetooth/l2cap_sock.c
>>> +++ b/net/bluetooth/l2cap_sock.c
>>> @@ -159,8 +159,23 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
>>> if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
>>> return -EINVAL;
>>>
>>> - if (chan->src_type == BDADDR_BREDR && la.l2_bdaddr_type != BDADDR_BREDR)
>>> - return -EINVAL;
>>> + if (chan->src_type == BDADDR_BREDR &&
>>> + la.l2_bdaddr_type != BDADDR_BREDR) {
>>> + if (!bdaddr_type_is_le(la.l2_bdaddr_type))
>>> + return -EINVAL;
>>
>> I do not understand this. The check for that la.l2_bdaddr_type is LE
>> is done twice here.
>
> The idea was simply to try to be forward compatible in case a fourth
> address type is added, i.e. I made the assumption that
> "a != BDADDR_BREDR" might not always be the same as "bdaddr_type_is_le(a)".
>
> If you're ok with this assumption we should not just remove this extra
> if-statement but also change the higher-level one to use
> bdaddr_type_is_le() instead of making explicit comparisons with
> BDADDR_BREDR.
we need to make this one old userspace exception work. Nothing else. From there on everything else will return -EINVAL.
It is the special case where we treat BDADDR_BREDR and only that one as "auto".
>>> +
>>> + /* Old user space versions will try to bind the ATT
>>> + * socket using BDADDR_BREDR, so we have to allow this
>>> + * to pass and fix chan->src_type to the correct value.
>>> + */
>>> + if (la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
>>> + return -EINVAL;
>>
>> I think we should also check that the src address is BDADDR_ANY. If it
>> is not BDADDR_ANY, we should reject it as well. That is enough to make
>> old userspace work. I do not want us to be any more flexible. Or are
>> we actually bind to the right source adapter when calling connect().
>
> The user space code is correct in this regard, so I'll add the extra
> check for BDADDR_ANY.
Translating this mean that even our current userspace is utterly broken when using LE and multiple controllers. The connection will always happen on first controller due to the binding to BDADDR_ANY.
Looking at src/device.c, then one case uses the adapter address with the correct address type of BDADDR_LE_PUBLIC and the other does not provide the address type. Which means it uses the correct adapter address, but BDADDR_BREDR.
Meaning we can not even check for BDADDR_ANY here. And actually BDADDR_ANY would have been the only one where all of this made sense. And where even internally this has to work since it is the default anyway since the structure is zeroed. And you need to be able to connect() without bind().
Btw. can someone fix BtIO to just spit out an error if either a source or destination address is provided, but no address type. That is just wrong and we should just fail on such code. All newer code should even provide BDADDR_BREDR for the case when we want to connect to BR/EDR devices.
>>> + if (chan->scid != L2CAP_CID_ATT)
>>> + return -EINVAL;
>>> +
>>> + chan->src_type = BDADDR_LE_PUBLIC;
>>> + }
>>
>> I do not like the fact that we are just defaulting to BDADDR_LE_PUBLIC
>> here. It might be fine since the old userspace only ever understood
>> public addresses anyway. However I do not like it that much. And if we
>> keep it this way, then a comment needs to explain that this is good
>> enough.
>
> I'll add a comment. We could in theory extend the code to also check for
> information inside the hdev struct, but that would require too much
> complexity for the benefit since we do not have the hdev available at
> this point in the socket operations. That, considered together with the
> fact that even now user space will have a hard-coded BDADDR_LE_PUBLIC is
> imo reason enough to just keep this simple in the kernel.
With a comment in the code why we stick to BDADDR_LE_PUBLIC here is fine with me.
Regards
Marcel
^ permalink raw reply
* Re: How to contribute
From: Luiz Augusto von Dentz @ 2013-10-18 7:48 UTC (permalink / raw)
To: Tim Wei; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CAKCXgJ25JzJ7H4sYdA6z7EFZYNC1OBpZ_rwPvLkgAirbqDd74A@mail.gmail.com>
Hi Tim,
On Fri, Oct 18, 2013 at 5:36 AM, Tim Wei <junping.wei@gmail.com> wrote:
> I just fixed a bug in kernel. How can I contribute it?
> My base version is Linux kernel 3.9.6. Should I download the latest
> kernel and check whether it has been fixed?
Any patch going upstream should probably be based on bluetooth-next:
https://git.kernel.org/cgit/linux/kernel/git/bluetooth/bluetooth-next.git/
Patches are expected to be send via git commit -s <try to be as
descriptive as possible in the commit message> + git format-patch +
git send-email like any other kernel patch and please be patient
sometimes the patches takes a while to be reviewed because the
maintainers are busy.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 1/8] Bluetooth: Add address type to device blacklist table
From: Johan Hedberg @ 2013-10-18 7:50 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1382055860-12572-1-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Thu, Oct 17, 2013, Marcel Holtmann wrote:
> The device blacklist is not taking care of the address type. Actually
> store the address type in the list entries and also use them when
> looking up addresses in the table.
>
> This is actually a serious bug. When adding a LE public address to
> the blacklist, then it would be blocking a device on BR/EDR. And this
> is not the expected behavior.
>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
> include/net/bluetooth/hci_core.h | 3 ++-
> net/bluetooth/hci_core.c | 21 +++++++++++----------
> net/bluetooth/hci_event.c | 2 +-
> 3 files changed, 14 insertions(+), 12 deletions(-)
All eight patches have been applied to bluetooth-next. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH] Bluetooth: Move idle_timeout and sniff_{min,max}_interval to hci_core.c
From: Johan Hedberg @ 2013-10-18 7:51 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1382062562-20113-1-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Thu, Oct 17, 2013, Marcel Holtmann wrote:
> Move the debugfs configuration directly into hci_core.c and only expose
> it when the controller actually support BR/EDR sniff power saving mode.
>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
> net/bluetooth/hci_core.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++
> net/bluetooth/hci_sysfs.c | 91 ----------------------------------------------
> 2 files changed, 93 insertions(+), 91 deletions(-)
Applied to bluetooth-next. Thanks.
Johan
^ permalink raw reply
* Re: [PATCHv2 2/2] android: Make toool compile on Android 4.2.2
From: Szymon Janc @ 2013-10-18 8:09 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381999828-29649-3-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> On our current target the tools cannot be compiled.
> ---
> android/Android.mk | 2 ++
> android/client/if-bt.c | 4 ++++
> android/client/if-main.h | 3 +++
> android/client/textconv.c | 2 ++
> 4 files changed, 11 insertions(+)
>
> diff --git a/android/Android.mk b/android/Android.mk
> index f59afc6..e63add9 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -92,6 +92,8 @@ LOCAL_SRC_FILES := \
> client/textconv.c \
> client/if-bt.c \
>
> +LOCAL_CFLAGS := -DPLATFORM_SDK_VERSION=$(PLATFORM_SDK_VERSION)
I suppose we should also define this for autotools build. Otherwise this
will not be build on Linux.
> +
> LOCAL_SHARED_LIBRARIES := libhardware
>
> LOCAL_MODULE_TAGS := optional
> diff --git a/android/client/if-bt.c b/android/client/if-bt.c
> index 90ef732..6aadeef 100644
> --- a/android/client/if-bt.c
> +++ b/android/client/if-bt.c
> @@ -277,7 +277,9 @@ static bt_callbacks_t bt_callbacks = {
> .acl_state_changed_cb = acl_state_changed_cb,
> .thread_evt_cb = thread_evt_cb,
> .dut_mode_recv_cb = dut_mode_recv_cb,
> +#if PLATFORM_SDK_VERSION > 17
> .le_test_mode_cb = le_test_mode_cb
> +#endif
> };
>
> static void init_p(int argc, const char **argv)
> @@ -577,8 +579,10 @@ static void get_profile_interface_p(int argc, const char **argv)
> pif = &dummy; /* TODO: change when if_hh is there */
> else if (strcmp(BT_PROFILE_PAN_ID, id) == 0)
> pif = &dummy; /* TODO: change when if_pan is there */
> +#if PLATFORM_SDK_VERSION > 17
> else if (strcmp(BT_PROFILE_AV_RC_ID, id) == 0)
> pif = &dummy; /* TODO: change when if_rc is there */
> +#endif
> else
> haltest_error("%s is not correct for get_profile_interface\n",
> id);
> diff --git a/android/client/if-main.h b/android/client/if-main.h
> index 9cac7ef..1cebb72 100644
> --- a/android/client/if-main.h
> +++ b/android/client/if-main.h
> @@ -35,7 +35,10 @@
> #include <hardware/bt_sock.h>
> #include <hardware/bt_hf.h>
> #include <hardware/bt_hl.h>
> +
> +#if PLATFORM_SDK_VERSION > 17
> #include <hardware/bt_rc.h>
> +#endif
>
> #include "textconv.h"
>
> diff --git a/android/client/textconv.c b/android/client/textconv.c
> index eebad70..f38e368 100644
> --- a/android/client/textconv.c
> +++ b/android/client/textconv.c
> @@ -94,7 +94,9 @@ INTMAP(bt_property_type_t, -1, "(unknown)")
> DELEMENT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT),
> DELEMENT(BT_PROPERTY_REMOTE_FRIENDLY_NAME),
> DELEMENT(BT_PROPERTY_REMOTE_RSSI),
> +#if PLATFORM_SDK_VERSION > 17
> DELEMENT(BT_PROPERTY_REMOTE_VERSION_INFO),
> +#endif
> DELEMENT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP),
> ENDMAP
>
>
--
BR
Szymon Janc
^ permalink raw reply
* [PATCH v2] Bluetooth: Fix ATT socket backwards compatibility with user space
From: johan.hedberg @ 2013-10-18 8:49 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
Old user space versions bind the Attribute Protocol socket to
BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or
BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the
socket parameters but we need to punch this hole for old user space
versions to keep them working.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_sock.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 34e5a58..1f326d9 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -159,8 +159,31 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
return -EINVAL;
- if (chan->src_type == BDADDR_BREDR && la.l2_bdaddr_type != BDADDR_BREDR)
- return -EINVAL;
+ /* Check that the socket wasn't bound to something that
+ * conflicts with the address given to connect(). If chan->src
+ * is BDADDR_ANY it means bind() was never used, in which case
+ * chan->src_type and la.l2_bdaddr_type do not need to match.
+ */
+ if (chan->src_type == BDADDR_BREDR && bacmp(&chan->src, BDADDR_ANY) &&
+ bdaddr_type_is_le(la.l2_bdaddr_type)) {
+ /* Old user space versions will try to incorrectly bind
+ * the ATT socket using BDADDR_BREDR. We need to accept
+ * this and fix up the source address type only when
+ * both the source CID and destination CID indicate
+ * ATT. Anything else is an invalid combination.
+ */
+ if (chan->scid != L2CAP_CID_ATT ||
+ la.l2_cid != __constant_cpu_to_le16(L2CAP_CID_ATT))
+ return -EINVAL;
+
+ /* We don't have the hdev available here to make a
+ * better decision on random vs public, but since all
+ * user space versions that exhibit this issue anyway do
+ * not support random local addresses assuming public
+ * here is good enough.
+ */
+ chan->src_type = BDADDR_LE_PUBLIC;
+ }
if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR)
return -EINVAL;
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH v2] Bluetooth: Fix ATT socket backwards compatibility with user space
From: Marcel Holtmann @ 2013-10-18 8:54 UTC (permalink / raw)
To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1382086165-24818-1-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
> Old user space versions bind the Attribute Protocol socket to
> BDADDR_BREDR when they should be using BDADDR_LE_PUBLIC or
> BDADDR_LE_RANDOM. The kernel recently introduced stricter checks on the
> socket parameters but we need to punch this hole for old user space
> versions to keep them working.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_sock.c | 27 +++++++++++++++++++++++++--
> 1 file changed, 25 insertions(+), 2 deletions(-)
patch has been applied to bluetooth-next tree.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Bluetooth: Add hci_h4p driver
From: Marcel Holtmann @ 2013-10-18 8:56 UTC (permalink / raw)
To: Pali Rohár; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <201310180739.47841@pali>
Hi Pali,
>>>> This driver adding support for Nokia N900 bluetooth
>>>> hardware
>>>>
>>>> Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
>>>> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
>>>> ---
>>>> drivers/bluetooth/Kconfig | 10 +
>>>> drivers/bluetooth/Makefile | 2 +
>>>> drivers/bluetooth/hci_h4p/Makefile | 7 +
>>>> drivers/bluetooth/hci_h4p/core.c | 1085
>>>> +++++++++++++++++++++++++++++++++
>>>> drivers/bluetooth/hci_h4p/fw-bcm.c | 149 +++++
>>>> drivers/bluetooth/hci_h4p/fw-csr.c | 152 +++++
>>>> drivers/bluetooth/hci_h4p/fw-ti1273.c | 113 ++++
>>>> drivers/bluetooth/hci_h4p/fw.c | 166 +++++
>>>> drivers/bluetooth/hci_h4p/hci_h4p.h | 238 ++++++++
>>>> drivers/bluetooth/hci_h4p/uart.c | 203 ++++++
>>>> include/linux/bluetooth/hci_h4p.h | 41 ++
>>>> 11 files changed, 2166 insertions(+)
>>>> create mode 100644 drivers/bluetooth/hci_h4p/Makefile
>>>> create mode 100644 drivers/bluetooth/hci_h4p/core.c
>>>> create mode 100644 drivers/bluetooth/hci_h4p/fw-bcm.c
>>>> create mode 100644 drivers/bluetooth/hci_h4p/fw-csr.c
>>>> create mode 100644 drivers/bluetooth/hci_h4p/fw-ti1273.c
>>>> create mode 100644 drivers/bluetooth/hci_h4p/fw.c
>>>> create mode 100644 drivers/bluetooth/hci_h4p/hci_h4p.h
>>>> create mode 100644 drivers/bluetooth/hci_h4p/uart.c
>>>> create mode 100644 include/linux/bluetooth/hci_h4p.h
>>>
>>> Can somebody look & comment this patch? What is needed to be
>>> part of upstream kernel?
>>
>> you need to rebase against bluetooth-next at least.
>
> Can you specify full url to that repo?
you can find that tree on git.kernel.org.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Bluetooth: Use BDADDR_BREDR type for old blacklist ioctl interface
From: Johan Hedberg @ 2013-10-18 9:27 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1382083828-23001-1-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Fri, Oct 18, 2013, Marcel Holtmann wrote:
> The old blacklist ioctl interface was only able to operate on BR/EDR
> addresses. So use the BDADDR_BREDR address type definition instead
> of an open coded magic 0 value.
>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
> net/bluetooth/hci_sock.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
Applied to bluetooth-next. Thanks.
Johan
^ permalink raw reply
* [PATCH BlueZ 1/2] build: Libify gobex
From: Luiz Augusto von Dentz @ 2013-10-18 10:16 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This enables tools/binaries to link directly with libgobex-internal.la
so gobex only need to be compiled once.
---
Makefile.am | 35 ++++++++++++++++++-----------------
Makefile.obexd | 4 ++--
Makefile.tools | 13 +++++++------
3 files changed, 27 insertions(+), 25 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 8aed6f7..816c071 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -102,12 +102,14 @@ attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
btio_sources = btio/btio.h btio/btio.c
-gobex_sources = gobex/gobex.h gobex/gobex.c \
- gobex/gobex-defs.h gobex/gobex-defs.c \
- gobex/gobex-packet.c gobex/gobex-packet.h \
- gobex/gobex-header.c gobex/gobex-header.h \
- gobex/gobex-transfer.c gobex/gobex-debug.h \
- gobex/gobex-apparam.c gobex/gobex-apparam.h
+noinst_LTLIBRARIES += gobex/libgobex-internal.la
+
+gobex_libgobex_internal_la_SOURCES = gobex/gobex.h gobex/gobex.c \
+ gobex/gobex-defs.h gobex/gobex-defs.c \
+ gobex/gobex-packet.c gobex/gobex-packet.h \
+ gobex/gobex-header.c gobex/gobex-header.h \
+ gobex/gobex-transfer.c gobex/gobex-debug.h \
+ gobex/gobex-apparam.c gobex/gobex-apparam.h
builtin_modules =
builtin_sources =
@@ -258,25 +260,24 @@ unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
unit/test-gobex-transfer unit/test-gobex-apparam
-unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
- unit/test-gobex.c
-unit_test_gobex_LDADD = @GLIB_LIBS@
+unit_test_gobex_SOURCES = unit/util.c unit/util.h unit/test-gobex.c
+unit_test_gobex_LDADD = gobex/libgobex-internal.la @GLIB_LIBS@
-unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+unit_test_gobex_packet_SOURCES = unit/util.c unit/util.h \
unit/test-gobex-packet.c
-unit_test_gobex_packet_LDADD = @GLIB_LIBS@
+unit_test_gobex_packet_LDADD = gobex/libgobex-internal.la @GLIB_LIBS@
-unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+unit_test_gobex_header_SOURCES = unit/util.c unit/util.h \
unit/test-gobex-header.c
-unit_test_gobex_header_LDADD = @GLIB_LIBS@
+unit_test_gobex_header_LDADD = gobex/libgobex-internal.la @GLIB_LIBS@
-unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+unit_test_gobex_transfer_SOURCES = unit/util.c unit/util.h \
unit/test-gobex-transfer.c
-unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+unit_test_gobex_transfer_LDADD = gobex/libgobex-internal.la @GLIB_LIBS@
-unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+unit_test_gobex_apparam_SOURCES = unit/util.c unit/util.h \
unit/test-gobex-apparam.c
-unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+unit_test_gobex_apparam_LDADD = gobex/libgobex-internal.la @GLIB_LIBS@
unit_tests += unit/test-lib
diff --git a/Makefile.obexd b/Makefile.obexd
index 3760867..1aad9ce 100644
--- a/Makefile.obexd
+++ b/Makefile.obexd
@@ -54,8 +54,7 @@ obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
libexec_PROGRAMS += obexd/src/obexd
-obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
- $(obexd_builtin_sources) \
+obexd_src_obexd_SOURCES = $(btio_sources) $(obexd_builtin_sources) \
obexd/src/main.c obexd/src/obexd.h \
obexd/src/plugin.h obexd/src/plugin.c \
obexd/src/log.h obexd/src/log.c \
@@ -81,6 +80,7 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
obexd/src/map_ap.h
obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
gdbus/libgdbus-internal.la \
+ gobex/libgobex-internal.la \
@ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
diff --git a/Makefile.tools b/Makefile.tools
index 840b95c..43bcf2e 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -227,14 +227,15 @@ attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
client/display.h
attrib_gatttool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lreadline
-tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \
- tools/obex-client-tool.c
+tools_obex_client_tool_SOURCES = $(btio_sources) tools/obex-client-tool.c
tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
- @GLIB_LIBS@ -lreadline
+ gobex/libgobex-internal.la \
+ @GLIB_LIBS@ -lreadline
-tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \
- tools/obex-server-tool.c
-tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+tools_obex_server_tool_SOURCES = $(btio_sources) tools/obex-server-tool.c
+tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \
+ gobex/libgobex-internal.la \
+ @GLIB_LIBS@
tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \
client/display.h client/display.c
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ 2/2] build: Libify btio
From: Luiz Augusto von Dentz @ 2013-10-18 10:16 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382091380-31518-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This enables tools/binaries to link directly with libbtio-internal.la
so btio only need to be compiled once.
---
Makefile.am | 13 ++++++++-----
Makefile.obexd | 3 ++-
Makefile.tools | 24 ++++++++++++++----------
3 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 816c071..f73176c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -100,7 +100,9 @@ attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
attrib/gattrib.h attrib/gattrib.c \
attrib/gatt-service.h attrib/gatt-service.c
-btio_sources = btio/btio.h btio/btio.c
+noinst_LTLIBRARIES += btio/libbtio-internal.la
+
+btio_libbtio_internal_la_SOURCES = btio/btio.h btio/btio.c
noinst_LTLIBRARIES += gobex/libgobex-internal.la
@@ -127,8 +129,7 @@ endif
libexec_PROGRAMS += src/bluetoothd
-src_bluetoothd_SOURCES = $(builtin_sources) \
- $(attrib_sources) $(btio_sources) \
+src_bluetoothd_SOURCES = $(builtin_sources) $(attrib_sources) \
src/bluetooth.ver \
src/main.c src/log.h src/log.c \
src/systemd.h src/systemd.c \
@@ -154,12 +155,14 @@ src_bluetoothd_SOURCES = $(builtin_sources) \
src/shared/util.h src/shared/util.c \
src/shared/mgmt.h src/shared/mgmt.c
src_bluetoothd_LDADD = lib/libbluetooth-internal.la gdbus/libgdbus-internal.la \
- @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
+ btio/libbtio-internal.la @GLIB_LIBS@ @DBUS_LIBS@ -ldl \
+ -lrt
src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
-Wl,--version-script=$(srcdir)/src/bluetooth.ver
src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
- gdbus/libgdbus-internal.la src/bluetooth.service
+ gdbus/libgdbus-internal.la \
+ btio/libbtio-internal.la src/bluetooth.service
src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
-DPLUGINDIR=\""$(build_plugindir)"\"
diff --git a/Makefile.obexd b/Makefile.obexd
index 1aad9ce..922b1b4 100644
--- a/Makefile.obexd
+++ b/Makefile.obexd
@@ -54,7 +54,7 @@ obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
libexec_PROGRAMS += obexd/src/obexd
-obexd_src_obexd_SOURCES = $(btio_sources) $(obexd_builtin_sources) \
+obexd_src_obexd_SOURCES = $(obexd_builtin_sources) \
obexd/src/main.c obexd/src/obexd.h \
obexd/src/plugin.h obexd/src/plugin.c \
obexd/src/log.h obexd/src/log.c \
@@ -81,6 +81,7 @@ obexd_src_obexd_SOURCES = $(btio_sources) $(obexd_builtin_sources) \
obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
gdbus/libgdbus-internal.la \
gobex/libgobex-internal.la \
+ btio/libbtio-internal.la \
@ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
diff --git a/Makefile.tools b/Makefile.tools
index 43bcf2e..c30b831 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -203,8 +203,9 @@ tools_btsnoop_SOURCES = tools/btsnoop.c \
src/shared/pcap.h src/shared/pcap.c \
src/shared/btsnoop.h src/shared/btsnoop.c
-tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
-tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+tools_btiotest_SOURCES = tools/btiotest.c
+tools_btiotest_LDADD = btio/libbtio-internal.la lib/libbluetooth-internal.la \
+ @GLIB_LIBS@
tools_mpris_player_SOURCES = tools/mpris-player.c
tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
@@ -221,19 +222,22 @@ noinst_PROGRAMS += attrib/gatttool \
tools/bluetooth-player tools/obexctl
attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
- attrib/gattrib.c btio/btio.c \
- attrib/gatttool.h attrib/interactive.c \
- attrib/utils.c src/log.c client/display.c \
+ attrib/gattrib.c attrib/gatttool.h \
+ attrib/interactive.c attrib/utils.c \
+ src/log.c client/display.c \
client/display.h
-attrib_gatttool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lreadline
+attrib_gatttool_LDADD = lib/libbluetooth-internal.la btio/libbtio-internal.la \
+ @GLIB_LIBS@ -lreadline
-tools_obex_client_tool_SOURCES = $(btio_sources) tools/obex-client-tool.c
-tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
+tools_obex_client_tool_SOURCES = tools/obex-client-tool.c
+tools_obex_client_tool_LDADD = btio/libbtio-internal.la \
+ lib/libbluetooth-internal.la \
gobex/libgobex-internal.la \
@GLIB_LIBS@ -lreadline
-tools_obex_server_tool_SOURCES = $(btio_sources) tools/obex-server-tool.c
-tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la \
+tools_obex_server_tool_SOURCES = tools/obex-server-tool.c
+tools_obex_server_tool_LDADD = btio/libbtio-internal.la \
+ lib/libbluetooth-internal.la \
gobex/libgobex-internal.la \
@GLIB_LIBS@
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] Bluetooth: Add hci_h4p driver
From: Pali Rohár @ 2013-10-18 10:30 UTC (permalink / raw)
To: Marcel Holtmann
Cc: Gustavo Padovan, Johan Hedberg, Pavel Machek, linux-kernel,
linux-bluetooth,
Ивайло Димитров,
Joni Lapilainen, Sebastian Reichel, Aaro Koskinen
In-Reply-To: <3B0F039C-4680-46FF-A654-48D6A28B9B5E@holtmann.org>
[-- Attachment #1: Type: Text/Plain, Size: 62533 bytes --]
On Friday 18 October 2013 00:11:44 Marcel Holtmann wrote:
> Hi Pali,
>
> >> This driver adding support for Nokia N900 bluetooth
> >> hardware
> >>
> >> Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
> >> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
> >> ---
> >> drivers/bluetooth/Kconfig | 10 +
> >> drivers/bluetooth/Makefile | 2 +
> >> drivers/bluetooth/hci_h4p/Makefile | 7 +
> >> drivers/bluetooth/hci_h4p/core.c | 1085
> >> +++++++++++++++++++++++++++++++++
> >> drivers/bluetooth/hci_h4p/fw-bcm.c | 149 +++++
> >> drivers/bluetooth/hci_h4p/fw-csr.c | 152 +++++
> >> drivers/bluetooth/hci_h4p/fw-ti1273.c | 113 ++++
> >> drivers/bluetooth/hci_h4p/fw.c | 166 +++++
> >> drivers/bluetooth/hci_h4p/hci_h4p.h | 238 ++++++++
> >> drivers/bluetooth/hci_h4p/uart.c | 203 ++++++
> >> include/linux/bluetooth/hci_h4p.h | 41 ++
> >> 11 files changed, 2166 insertions(+)
> >> create mode 100644 drivers/bluetooth/hci_h4p/Makefile
> >> create mode 100644 drivers/bluetooth/hci_h4p/core.c
> >> create mode 100644 drivers/bluetooth/hci_h4p/fw-bcm.c
> >> create mode 100644 drivers/bluetooth/hci_h4p/fw-csr.c
> >> create mode 100644 drivers/bluetooth/hci_h4p/fw-ti1273.c
> >> create mode 100644 drivers/bluetooth/hci_h4p/fw.c
> >> create mode 100644 drivers/bluetooth/hci_h4p/hci_h4p.h
> >> create mode 100644 drivers/bluetooth/hci_h4p/uart.c
> >> create mode 100644 include/linux/bluetooth/hci_h4p.h
> >
> > Can somebody look & comment this patch? What is needed to be
> > part of upstream kernel?
>
> you need to rebase against bluetooth-next at least.
>
> Regards
>
> Marcel
I rebased patch on top of https://git.kernel.org/cgit/linux/kernel/git/bluetooth/bluetooth-next.git branch master
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 11a6104..95155c3 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -242,4 +242,14 @@ config BT_WILINK
Say Y here to compile support for Texas Instrument's WiLink7 driver
into the kernel or say M to compile it as module.
+
+config BT_HCIH4P
+ tristate "HCI driver with H4 Nokia extensions"
+ depends on BT && ARCH_OMAP
+ help
+ Bluetooth HCI driver with H4 extensions. This driver provides
+ support for H4+ Bluetooth chip with vendor-specific H4 extensions.
+
+ Say Y here to compile support for h4 extended devices into the kernel
+ or say M to compile it as module (hci_h4p).
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 9fe8a87..46759f1 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -20,6 +20,8 @@ obj-$(CONFIG_BT_MRVL) += btmrvl.o
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
obj-$(CONFIG_BT_WILINK) += btwilink.o
+obj-y += hci_h4p/
+
btmrvl-y := btmrvl_main.o
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
diff --git a/drivers/bluetooth/hci_h4p/Makefile b/drivers/bluetooth/hci_h4p/Makefile
new file mode 100644
index 0000000..f20bd9a
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux Bluetooth HCI device drivers.
+#
+
+obj-$(CONFIG_BT_HCIH4P) += hci_h4p.o
+
+hci_h4p-objs := core.o fw.o uart.o fw-csr.o fw-bcm.o fw-ti1273.o
diff --git a/drivers/bluetooth/hci_h4p/core.c b/drivers/bluetooth/hci_h4p/core.c
new file mode 100644
index 0000000..13a1243
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/core.c
@@ -0,0 +1,1076 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/serial_reg.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/bluetooth/hci_h4p.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#include "hci_h4p.h"
+
+static void hci_h4p_set_clk(struct hci_h4p_info *info, int *clock, int enable)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->clocks_lock, flags);
+ if (enable && !*clock) {
+ NBT_DBG_POWER("Enabling %p\n", clock);
+ clk_prepare_enable(info->uart_fclk);
+ clk_prepare_enable(info->uart_iclk);
+ if (atomic_read(&info->clk_users) == 0)
+ hci_h4p_restore_regs(info);
+ atomic_inc(&info->clk_users);
+ }
+
+ if (!enable && *clock) {
+ NBT_DBG_POWER("Disabling %p\n", clock);
+ if (atomic_dec_and_test(&info->clk_users))
+ hci_h4p_store_regs(info);
+ clk_disable_unprepare(info->uart_fclk);
+ clk_disable_unprepare(info->uart_iclk);
+ }
+
+ *clock = enable;
+ spin_unlock_irqrestore(&info->clocks_lock, flags);
+}
+
+/* Power management functions */
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable)
+{
+ u8 v;
+
+ return;
+
+ v = hci_h4p_inb(info, UART_OMAP_SYSC);
+ v &= ~(UART_OMAP_SYSC_IDLEMASK);
+
+ if (enable)
+ v |= UART_OMAP_SYSC_SMART_IDLE;
+ else
+ v |= UART_OMAP_SYSC_NO_IDLE;
+
+ hci_h4p_outb(info, UART_OMAP_SYSC, v);
+}
+
+static void hci_h4p_disable_tx(struct hci_h4p_info *info)
+{
+ NBT_DBG_POWER("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ hci_h4p_smart_idle(info, 1);
+
+ info->bt_wakeup(0);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ info->tx_enabled = 0;
+}
+
+void hci_h4p_enable_tx(struct hci_h4p_info *info)
+{
+ NBT_DBG_POWER("\n");
+
+ if (!info->pm_enabled)
+ return;
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ info->tx_enabled = 1;
+ hci_h4p_smart_idle(info, 0);
+ info->bt_wakeup(1);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+}
+
+static void hci_h4p_disable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ info->rx_enabled = 0;
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ NBT_DBG("data ready postpone autorts");
+ return;
+ }
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+ NBT_DBG("trasmitter not empty postpone autorts");
+ return;
+ }
+
+ hci_h4p_set_rts(info, info->rx_enabled);
+ __hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ info->autorts = 0;
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_enable_rx(struct hci_h4p_info *info)
+{
+ if (!info->pm_enabled)
+ return;
+
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ info->rx_enabled = 1;
+
+ hci_h4p_set_rts(info, 1);
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) {
+ NBT_DBG("trasmitter not empty postpone autorts");
+ return;
+ }
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ NBT_DBG("data ready postpone autorts");
+ return;
+ }
+
+ __hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ info->autorts = 1;
+}
+
+/* Negotiation functions */
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info)
+{
+ struct hci_h4p_alive_hdr *alive_hdr;
+ struct hci_h4p_alive_msg *alive_cmd;
+ struct sk_buff *skb;
+ unsigned long flags;
+
+ NBT_DBG("Sending alive packet\n");
+
+ skb = bt_skb_alloc(HCI_H4P_ALIVE_HDR_SIZE + HCI_H4P_ALIVE_MSG_SIZE, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ alive_hdr = (void *) skb_put(skb, HCI_H4P_ALIVE_HDR_SIZE);
+ alive_hdr->dlen = HCI_H4P_ALIVE_MSG_SIZE;
+ alive_cmd = (void *) skb_put(skb, HCI_H4P_ALIVE_MSG_SIZE);
+ alive_cmd->message_id = HCI_H4P_ALIVE_IND_REQ;
+ alive_cmd->unused = 0x00;
+ *skb_push(skb, 1) = H4_ALIVE_PKT;
+
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ NBT_DBG("Alive packet sent\n");
+
+ return 0;
+}
+
+static void hci_h4p_alive_packet(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ struct hci_h4p_alive_hdr *alive_hdr = (void *) skb->data;
+ struct hci_h4p_alive_msg *alive_evt;
+
+ if (alive_hdr->dlen > skb->len) {
+ info->init_error = -EPROTO;
+ complete(&info->init_completion);
+ return;
+ }
+
+ alive_evt = (void *) skb_pull(skb, HCI_H4P_ALIVE_HDR_SIZE);
+
+ NBT_DBG("Received alive packet\n");
+ if (alive_evt->message_id != HCI_H4P_ALIVE_IND_RESP) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+static int hci_h4p_send_negotiation(struct hci_h4p_info *info)
+{
+ struct hci_h4p_init_cmd *init_cmd;
+ struct hci_h4p_init_hdr *init_hdr;
+ struct sk_buff *skb;
+ unsigned long flags;
+ int err;
+
+ NBT_DBG("Sending negotiation..\n");
+
+ skb = bt_skb_alloc(HCI_H4P_INIT_HDR_SIZE + HCI_H4P_INIT_CMD_SIZE, GFP_KERNEL);
+ if (!skb)
+ return -ENOMEM;
+
+ init_hdr = (void *)skb_put(skb, HCI_H4P_INIT_HDR_SIZE);
+ init_hdr->dlen = HCI_H4P_INIT_CMD_SIZE;
+ init_cmd = (void *)skb_put(skb, HCI_H4P_INIT_CMD_SIZE);
+ init_cmd->ack = 0x00;
+ init_cmd->baudrate = cpu_to_le16(0x01a1);
+ init_cmd->unused = cpu_to_le16(0x0000);
+ init_cmd->mode = HCI_H4P_MODE;
+ init_cmd->sys_clk = cpu_to_le16(0x9600);
+ init_cmd->unused2 = cpu_to_le16(0x0000);
+ *skb_push(skb, 1) = H4_NEG_PKT;
+
+ hci_h4p_change_speed(info, INIT_SPEED);
+
+ hci_h4p_set_rts(info, 1);
+ info->init_error = 0;
+ init_completion(&info->init_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ /* Change to operational settings */
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, MAX_BAUD_RATE);
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0)
+ return err;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+ init_completion(&info->init_completion);
+ err = hci_h4p_send_alive_packet(info);
+
+ if (err < 0)
+ return err;
+
+ if (!wait_for_completion_interruptible_timeout(&info->init_completion,
+ msecs_to_jiffies(1000)))
+ return -ETIMEDOUT;
+
+ if (info->init_error < 0)
+ return info->init_error;
+
+ NBT_DBG("Negotiation succesful\n");
+ return 0;
+}
+
+static void hci_h4p_negotiation_packet(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct hci_h4p_init_hdr *init_hdr = (void *) skb->data;
+ struct hci_h4p_init_evt *init_evt;
+
+ if (init_hdr->dlen > skb->len) {
+ kfree_skb(skb);
+ info->init_error = -EPROTO;
+ complete(&info->init_completion);
+ return;
+ }
+
+ init_evt = (void *)skb_pull(skb, HCI_H4P_INIT_HDR_SIZE);
+
+ if (init_evt->ack != HCI_H4P_ACK) {
+ dev_err(info->dev, "Could not negotiate hci_h4p settings\n");
+ info->init_error = -EINVAL;
+ }
+
+ info->man_id = init_evt->man_id;
+ info->ver_id = init_evt->ver_id;
+
+ complete(&info->init_completion);
+ kfree_skb(skb);
+}
+
+/* H4 packet handling functions */
+static int hci_h4p_get_hdr_len(struct hci_h4p_info *info, u8 pkt_type)
+{
+ long retval;
+
+ switch (pkt_type) {
+ case H4_EVT_PKT:
+ retval = HCI_EVENT_HDR_SIZE;
+ break;
+ case H4_ACL_PKT:
+ retval = HCI_ACL_HDR_SIZE;
+ break;
+ case H4_SCO_PKT:
+ retval = HCI_SCO_HDR_SIZE;
+ break;
+ case H4_NEG_PKT:
+ retval = HCI_H4P_INIT_HDR_SIZE;
+ break;
+ case H4_ALIVE_PKT:
+ retval = HCI_H4P_ALIVE_HDR_SIZE;
+ break;
+ case H4_RADIO_PKT:
+ retval = H4_RADIO_HDR_SIZE;
+ break;
+ default:
+ dev_err(info->dev, "Unknown H4 packet type 0x%.2x\n", pkt_type);
+ retval = -1;
+ break;
+ }
+
+ return retval;
+}
+
+static unsigned int hci_h4p_get_data_len(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ long retval = -1;
+ struct hci_event_hdr *evt_hdr;
+ struct hci_acl_hdr *acl_hdr;
+ struct hci_sco_hdr *sco_hdr;
+ struct hci_h4p_radio_hdr *radio_hdr;
+ struct hci_h4p_init_hdr *init_hdr;
+ struct hci_h4p_alive_hdr *alive_hdr;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case H4_EVT_PKT:
+ evt_hdr = (struct hci_event_hdr *)skb->data;
+ retval = evt_hdr->plen;
+ break;
+ case H4_ACL_PKT:
+ acl_hdr = (struct hci_acl_hdr *)skb->data;
+ retval = le16_to_cpu(acl_hdr->dlen);
+ break;
+ case H4_SCO_PKT:
+ sco_hdr = (struct hci_sco_hdr *)skb->data;
+ retval = sco_hdr->dlen;
+ break;
+ case H4_RADIO_PKT:
+ radio_hdr = (struct hci_h4p_radio_hdr *)skb->data;
+ retval = radio_hdr->dlen;
+ break;
+ case H4_NEG_PKT:
+ init_hdr = (struct hci_h4p_init_hdr *)skb->data;
+ retval = init_hdr->dlen;
+ break;
+ case H4_ALIVE_PKT:
+ alive_hdr = (struct hci_h4p_alive_hdr *)skb->data;
+ retval = alive_hdr->dlen;
+ break;
+ }
+
+ return retval;
+}
+
+static inline void hci_h4p_recv_frame(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+
+ if (unlikely(!test_bit(HCI_RUNNING, &info->hdev->flags))) {
+ NBT_DBG("fw_event\n");
+ if (bt_cb(info->rx_skb)->pkt_type == H4_NEG_PKT) {
+ hci_h4p_negotiation_packet(info, info->rx_skb);
+ return;
+ }
+ if (bt_cb(info->rx_skb)->pkt_type == H4_ALIVE_PKT) {
+ hci_h4p_alive_packet(info, info->rx_skb);
+ return;
+ }
+ hci_h4p_parse_fw_event(info, skb);
+ } else {
+ hci_recv_frame(info->hdev, skb);
+ NBT_DBG("Frame sent to upper layer\n");
+ }
+}
+
+static inline void hci_h4p_handle_byte(struct hci_h4p_info *info, u8 byte)
+{
+ switch (info->rx_state) {
+ case WAIT_FOR_PKT_TYPE:
+ bt_cb(info->rx_skb)->pkt_type = byte;
+ info->rx_count = hci_h4p_get_hdr_len(info, byte);
+ if (info->rx_count < 0) {
+ info->hdev->stat.err_rx++;
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ } else {
+ info->rx_state = WAIT_FOR_HEADER;
+ }
+ break;
+ case WAIT_FOR_HEADER:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ if (info->rx_count != 0)
+ break;
+
+ info->rx_count = hci_h4p_get_data_len(info,
+ info->rx_skb);
+ if (info->rx_count > skb_tailroom(info->rx_skb)) {
+ dev_err(info->dev, "Too long frame.\n");
+ info->garbage_bytes = info->rx_count -
+ skb_tailroom(info->rx_skb);
+ kfree_skb(info->rx_skb);
+ info->rx_skb = NULL;
+ break;
+ }
+ info->rx_state = WAIT_FOR_DATA;
+ break;
+ case WAIT_FOR_DATA:
+ info->rx_count--;
+ *skb_put(info->rx_skb, 1) = byte;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ if (info->rx_count == 0) {
+ /* H4+ devices should allways send word aligned
+ * packets */
+ if (!(info->rx_skb->len % 2))
+ info->garbage_bytes++;
+ hci_h4p_recv_frame(info, info->rx_skb);
+ info->rx_skb = NULL;
+ }
+}
+
+static void hci_h4p_rx(unsigned long data)
+{
+ u8 byte;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ NBT_DBG("rx woke up\n");
+
+ while (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR) {
+ byte = hci_h4p_inb(info, UART_RX);
+ if (info->garbage_bytes) {
+ info->garbage_bytes--;
+ continue;
+ }
+ if (info->rx_skb == NULL) {
+ info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE,
+ GFP_ATOMIC);
+ if (!info->rx_skb) {
+ dev_err(info->dev,
+ "No memory for new packet\n");
+ return;
+ }
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ }
+ info->hdev->stat.byte_rx++;
+ NBT_DBG_TRANSFER_NF("0x%.2x ", byte);
+ hci_h4p_handle_byte(info, byte);
+ }
+
+ if (info->rx_enabled == info->autorts)
+ return;
+
+ if (!(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT))
+ return;
+
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)
+ return;
+
+ hci_h4p_set_rts(info, info->rx_enabled);
+ __hci_h4p_set_auto_ctsrts(info, info->rx_enabled, UART_EFR_RTS);
+ info->autorts = info->rx_enabled;
+
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+}
+
+static void hci_h4p_tx(unsigned long data)
+{
+ unsigned int sent = 0;
+ struct sk_buff *skb;
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+
+ NBT_DBG("tx woke up\n");
+ NBT_DBG_TRANSFER("data ");
+
+ if (info->autorts != info->rx_enabled) {
+ NBT_DBG("rts unbalanced.. autorts %d rx_enabled %d", info->autorts, info->rx_enabled);
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT &&
+ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_DR)) {
+ __hci_h4p_set_auto_ctsrts(info, info->rx_enabled,
+ UART_EFR_RTS);
+ info->autorts = info->rx_enabled;
+ hci_h4p_set_rts(info, info->rx_enabled);
+ hci_h4p_set_clk(info, &info->rx_clocks_en,
+ info->rx_enabled);
+ NBT_DBG("transmitter empty. setinng into balance\n");
+ } else {
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ NBT_DBG("transmitter/receiver was not empty waiting for next irq\n");
+ hci_h4p_set_rts(info, 1);
+ goto finish_tx;
+ }
+ }
+
+ skb = skb_dequeue(&info->txq);
+ if (!skb) {
+ /* No data in buffer */
+ NBT_DBG("skb ready\n");
+ if (hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT) {
+ hci_h4p_outb(info, UART_IER,
+ hci_h4p_inb(info, UART_IER) &
+ ~UART_IER_THRI);
+ hci_h4p_inb(info, UART_OMAP_SCR);
+ hci_h4p_disable_tx(info);
+ NBT_DBG("transmitter was empty. cleaning up\n");
+ return;
+ }
+ hci_h4p_outb(info, UART_OMAP_SCR,
+ hci_h4p_inb(info, UART_OMAP_SCR) |
+ UART_OMAP_SCR_EMPTY_THR);
+ NBT_DBG("transmitter was not empty waiting for next irq\n");
+ goto finish_tx;
+ }
+
+ /* Copy data to tx fifo */
+ while (!(hci_h4p_inb(info, UART_OMAP_SSR) & UART_OMAP_SSR_TXFULL) &&
+ (sent < skb->len)) {
+ NBT_DBG_TRANSFER_NF("0x%.2x ", skb->data[sent]);
+ hci_h4p_outb(info, UART_TX, skb->data[sent]);
+ sent++;
+ }
+
+ info->hdev->stat.byte_tx += sent;
+ if (skb->len == sent) {
+ kfree_skb(skb);
+ } else {
+ skb_pull(skb, sent);
+ skb_queue_head(&info->txq, skb);
+ }
+
+ hci_h4p_outb(info, UART_OMAP_SCR, hci_h4p_inb(info, UART_OMAP_SCR) &
+ ~UART_OMAP_SCR_EMPTY_THR);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+
+finish_tx:
+ /* Flush posted write to avoid spurious interrupts */
+ hci_h4p_inb(info, UART_OMAP_SCR);
+
+}
+
+static irqreturn_t hci_h4p_interrupt(int irq, void *data)
+{
+ struct hci_h4p_info *info = (struct hci_h4p_info *)data;
+ u8 iir, msr;
+ int ret;
+
+ ret = IRQ_NONE;
+
+ iir = hci_h4p_inb(info, UART_IIR);
+ if (iir & UART_IIR_NO_INT)
+ return IRQ_HANDLED;
+
+ NBT_DBG("In interrupt handler iir 0x%.2x\n", iir);
+
+ iir &= UART_IIR_ID;
+
+ if (iir == UART_IIR_MSI) {
+ msr = hci_h4p_inb(info, UART_MSR);
+ ret = IRQ_HANDLED;
+ }
+ if (iir == UART_IIR_RLSI) {
+ hci_h4p_inb(info, UART_RX);
+ hci_h4p_inb(info, UART_LSR);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_RDI) {
+ hci_h4p_rx((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ if (iir == UART_IIR_THRI) {
+ hci_h4p_tx((unsigned long)data);
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static irqreturn_t hci_h4p_wakeup_interrupt(int irq, void *dev_inst)
+{
+ struct hci_h4p_info *info = dev_inst;
+ int should_wakeup;
+ struct hci_dev *hdev;
+
+ if (!info->hdev)
+ return IRQ_HANDLED;
+
+ hdev = info->hdev;
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return IRQ_HANDLED;
+
+ should_wakeup = info->host_wakeup();
+ NBT_DBG_POWER("gpio interrupt %d\n", should_wakeup);
+
+ /* Check if wee have missed some interrupts */
+ if (info->rx_enabled == should_wakeup)
+ return IRQ_HANDLED;
+
+ if (should_wakeup)
+ hci_h4p_enable_rx(info);
+ else
+ hci_h4p_disable_rx(info);
+
+ return IRQ_HANDLED;
+}
+
+static int hci_h4p_reset(struct hci_h4p_info *info)
+{
+ int err;
+
+ err = hci_h4p_reset_uart(info);
+ if (err < 0) {
+ dev_err(info->dev, "Uart reset failed\n");
+ return err;
+ }
+ hci_h4p_init_uart(info);
+ hci_h4p_set_rts(info, 0);
+
+ info->reset(0);
+ info->bt_wakeup(1);
+ msleep(10);
+ info->reset(1);
+
+ err = hci_h4p_wait_for_cts(info, 1, 100);
+ if (err < 0) {
+ dev_err(info->dev, "No cts from bt chip\n");
+ return err;
+ }
+
+ hci_h4p_set_rts(info, 1);
+
+ return 0;
+}
+
+/* hci callback functions */
+static int hci_h4p_hci_flush(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ info = hci_get_drvdata(hdev);
+
+ skb_queue_purge(&info->txq);
+
+ return 0;
+}
+
+static int hci_h4p_hci_open(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info;
+ int err;
+ struct sk_buff_head fw_queue;
+ unsigned long flags;
+
+ info = hci_get_drvdata(hdev);
+
+ if (test_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ info->rx_enabled = 1;
+ info->rx_state = WAIT_FOR_PKT_TYPE;
+ info->rx_count = 0;
+ info->garbage_bytes = 0;
+ info->rx_skb = NULL;
+ info->pm_enabled = 0;
+ init_completion(&info->fw_completion);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ skb_queue_head_init(&fw_queue);
+
+ err = hci_h4p_reset(info);
+ if (err < 0)
+ goto err_clean;
+
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_CTS | UART_EFR_RTS);
+ info->autorts = 1;
+ err = hci_h4p_send_negotiation(info);
+ if (err < 0)
+ goto err_clean;
+
+ skb_queue_head_init(&fw_queue);
+ err = hci_h4p_read_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Cannot read firmware\n");
+ return err;
+ }
+
+ /* FW image contains also unneeded negoation and alive msgs */
+ skb_dequeue(&fw_queue);
+ skb_dequeue(&fw_queue);
+
+ err = hci_h4p_send_fw(info, &fw_queue);
+ if (err < 0) {
+ dev_err(info->dev, "Sending firmware failed.\n");
+ goto err_clean;
+ }
+
+ info->pm_enabled = 1;
+
+ spin_lock_irqsave(&info->lock, flags);
+ info->rx_enabled = info->host_wakeup();
+ hci_h4p_set_clk(info, &info->rx_clocks_en, info->rx_enabled);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ set_bit(HCI_RUNNING, &hdev->flags);
+
+ NBT_DBG("hci up and running\n");
+ return 0;
+
+err_clean:
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_reset_uart(info);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ info->reset(0);
+ info->bt_wakeup(0);
+ skb_queue_purge(&fw_queue);
+ kfree_skb(info->rx_skb);
+
+ return err;
+}
+
+static int hci_h4p_hci_close(struct hci_dev *hdev)
+{
+ struct hci_h4p_info *info = hci_get_drvdata(hdev);
+
+ if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
+ return 0;
+
+ hci_h4p_hci_flush(hdev);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 1);
+ hci_h4p_reset_uart(info);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+ hci_h4p_set_clk(info, &info->rx_clocks_en, 0);
+ info->reset(0);
+ info->bt_wakeup(0);
+ kfree_skb(info->rx_skb);
+
+ return 0;
+}
+
+static int hci_h4p_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct hci_h4p_info *info;
+ int err = 0;
+ unsigned long flags;
+
+ if (!hdev) {
+ printk(KERN_WARNING "hci_h4p: Frame for unknown device\n");
+ return -ENODEV;
+ }
+
+ NBT_DBG("dev %p, skb %p\n", hdev, skb);
+
+ info = hci_get_drvdata(hdev);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+ dev_warn(info->dev, "Frame for non-running device\n");
+ return -EIO;
+ }
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ hdev->stat.cmd_tx++;
+ break;
+ case HCI_ACLDATA_PKT:
+ hdev->stat.acl_tx++;
+ break;
+ case HCI_SCODATA_PKT:
+ hdev->stat.sco_tx++;
+ break;
+ }
+
+ /* Push frame type to skb */
+ *skb_push(skb, 1) = (bt_cb(skb)->pkt_type);
+ /* We should allways send word aligned data to h4+ devices */
+ if (skb->len % 2) {
+ err = skb_pad(skb, 1);
+ if (!err)
+ *skb_put(skb, 1) = 0x00;
+ }
+ if (err)
+ return err;
+
+ spin_lock_irqsave(&info->lock, flags);
+ skb_queue_tail(&info->txq, skb);
+ hci_h4p_enable_tx(info);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ return 0;
+}
+
+static int hci_h4p_register_hdev(struct hci_h4p_info *info)
+{
+ struct hci_dev *hdev;
+
+ /* Initialize and register HCI device */
+
+ hdev = hci_alloc_dev();
+ if (!hdev) {
+ dev_err(info->dev, "Can't allocate memory for device\n");
+ return -ENOMEM;
+ }
+ info->hdev = hdev;
+
+ hdev->bus = HCI_UART;
+ hci_set_drvdata(hdev, info);
+
+ hdev->open = hci_h4p_hci_open;
+ hdev->close = hci_h4p_hci_close;
+ hdev->flush = hci_h4p_hci_flush;
+ hdev->send = hci_h4p_hci_send_frame;
+ set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+ SET_HCIDEV_DEV(hdev, info->dev);
+
+ if (hci_register_dev(hdev) < 0) {
+ dev_err(info->dev, "hci_register failed %s.\n", hdev->name);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static ssize_t hci_h4p_store_bdaddr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+ unsigned int bdaddr[6];
+ int ret, i;
+
+ ret = sscanf(buf, "%2x:%2x:%2x:%2x:%2x:%2x\n",
+ &bdaddr[0], &bdaddr[1], &bdaddr[2],
+ &bdaddr[3], &bdaddr[4], &bdaddr[5]);
+
+ if (ret != 6)
+ return -EINVAL;
+
+ for (i = 0; i < 6; i++)
+ info->bd_addr[i] = bdaddr[i] & 0xff;
+
+ return count;
+}
+
+static ssize_t hci_h4p_show_bdaddr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hci_h4p_info *info = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
+ info->bd_addr[0], info->bd_addr[1], info->bd_addr[2],
+ info->bd_addr[3], info->bd_addr[4], info->bd_addr[5]);
+}
+
+static DEVICE_ATTR(bdaddr, S_IRUGO | S_IWUSR, hci_h4p_show_bdaddr,
+ hci_h4p_store_bdaddr);
+
+static int hci_h4p_sysfs_create_files(struct device *dev)
+{
+ return device_create_file(dev, &dev_attr_bdaddr);
+}
+
+static void hci_h4p_sysfs_remove_files(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_bdaddr);
+}
+
+static int hci_h4p_probe(struct platform_device *pdev)
+{
+ struct hci_h4p_platform_data *bt_plat_data;
+ struct hci_h4p_info *info;
+ int err;
+
+ dev_info(&pdev->dev, "Registering HCI H4P device\n");
+ info = kzalloc(sizeof(struct hci_h4p_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = &pdev->dev;
+ info->pm_enabled = 0;
+ info->tx_enabled = 1;
+ info->rx_enabled = 1;
+ info->garbage_bytes = 0;
+ info->tx_clocks_en = 0;
+ info->rx_clocks_en = 0;
+ spin_lock_init(&info->lock);
+ spin_lock_init(&info->clocks_lock);
+ skb_queue_head_init(&info->txq);
+
+ if (pdev->dev.platform_data == NULL) {
+ dev_err(&pdev->dev, "Could not get Bluetooth config data\n");
+ kfree(info);
+ return -ENODATA;
+ }
+
+ bt_plat_data = pdev->dev.platform_data;
+ info->chip_type = 3;
+ info->bt_wakeup = bt_plat_data->bt_wu;
+ info->host_wakeup = bt_plat_data->host_wu;
+ info->reset = bt_plat_data->reset;
+ info->uart_base = bt_plat_data->uart_base;
+ info->host_wakeup_gpio = bt_plat_data->host_wu_gpio;
+
+ NBT_DBG("RESET gpio: %p\n", info->reset);
+ NBT_DBG("BTWU gpio: %p\n", info->bt_wakeup);
+ NBT_DBG("HOSTWU gpio: %p\n", info->host_wakeup);
+
+ info->irq = bt_plat_data->uart_irq;
+ err = request_irq(info->irq, hci_h4p_interrupt, IRQF_DISABLED | IRQF_SHARED,
+ "hci_h4p", info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get IRQ %d\n", info->irq);
+ goto cleanup;
+ }
+
+ err = request_irq(gpio_to_irq(info->host_wakeup_gpio),
+ hci_h4p_wakeup_interrupt, IRQF_TRIGGER_FALLING |
+ IRQF_TRIGGER_RISING | IRQF_DISABLED,
+ "hci_h4p_wkup", info);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to get wakeup IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ free_irq(info->irq, info);
+ goto cleanup;
+ }
+
+ err = irq_set_irq_wake(gpio_to_irq(info->host_wakeup_gpio), 1);
+ if (err < 0) {
+ dev_err(info->dev, "hci_h4p: unable to set wakeup for IRQ %d\n",
+ gpio_to_irq(info->host_wakeup_gpio));
+ free_irq(info->irq, info);
+ free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+ goto cleanup;
+ }
+
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 1);
+ err = hci_h4p_reset_uart(info);
+ if (err < 0)
+ goto cleanup_irq;
+ hci_h4p_init_uart(info);
+ hci_h4p_set_rts(info, 0);
+ err = hci_h4p_reset(info);
+ hci_h4p_reset_uart(info);
+ if (err < 0)
+ goto cleanup_irq;
+ info->reset(0);
+ hci_h4p_set_clk(info, &info->tx_clocks_en, 0);
+
+ platform_set_drvdata(pdev, info);
+
+ if (hci_h4p_sysfs_create_files(info->dev) < 0) {
+ dev_err(info->dev, "failed to create sysfs files\n");
+ goto cleanup_irq;
+ }
+
+ if (hci_h4p_register_hdev(info) < 0) {
+ dev_err(info->dev, "failed to register hci_h4p hci device\n");
+ goto cleanup_sysfs;
+ }
+
+ return 0;
+
+cleanup_sysfs:
+ hci_h4p_sysfs_remove_files(info->dev);
+cleanup_irq:
+ free_irq(info->irq, (void *)info);
+ free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+cleanup:
+ info->reset(0);
+ kfree(info);
+ return err;
+
+}
+
+static int hci_h4p_remove(struct platform_device *pdev)
+{
+ struct hci_h4p_info *info;
+
+ info = platform_get_drvdata(pdev);
+
+ hci_h4p_sysfs_remove_files(info->dev);
+ hci_h4p_hci_close(info->hdev);
+ free_irq(gpio_to_irq(info->host_wakeup_gpio), info);
+ hci_unregister_dev(info->hdev);
+ hci_free_dev(info->hdev);
+ free_irq(info->irq, (void *) info);
+ kfree(info);
+
+ return 0;
+}
+
+static struct platform_driver hci_h4p_driver = {
+ .probe = hci_h4p_probe,
+ .remove = hci_h4p_remove,
+ .driver = {
+ .name = "hci_h4p",
+ },
+};
+
+static int __init hci_h4p_init(void)
+{
+ int err = 0;
+
+ /* Register the driver with LDM */
+ err = platform_driver_register(&hci_h4p_driver);
+ if (err < 0)
+ printk(KERN_WARNING "failed to register hci_h4p driver\n");
+
+ return err;
+}
+
+static void __exit hci_h4p_exit(void)
+{
+ platform_driver_unregister(&hci_h4p_driver);
+}
+
+module_init(hci_h4p_init);
+module_exit(hci_h4p_exit);
+
+MODULE_ALIAS("platform:hci_h4p");
+MODULE_DESCRIPTION("Bluetooth h4 driver with nokia extensions");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ville Tervo");
+MODULE_FIRMWARE(FW_NAME_CSR);
+MODULE_FIRMWARE(FW_NAME_TI);
+MODULE_FIRMWARE(FW_NAME_BCM);
diff --git a/drivers/bluetooth/hci_h4p/fw-bcm.c b/drivers/bluetooth/hci_h4p/fw-bcm.c
new file mode 100644
index 0000000..56684f8
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-bcm.c
@@ -0,0 +1,149 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static int hci_h4p_bcm_set_bdaddr(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ static const u8 nokia_oui[3] = {0x00, 0x1f, 0xdf};
+ int not_valid;
+ int i;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found, setting some random\n");
+ /* When address is not valid, use some random but Nokia MAC */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ for (i = 0; i < 6; i++)
+ skb->data[9 - i] = info->bd_addr[i];
+
+ return 0;
+}
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ int err;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(info->fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ if (fw_skb->data[1] == 0x01 && fw_skb->data[2] == 0xfc && fw_skb->len >= 10) {
+ NBT_DBG_FW("Setting bluetooth address\n");
+ err = hci_h4p_bcm_set_bdaddr(info, fw_skb);
+ if (err < 0) {
+ kfree_skb(fw_skb);
+ info->fw_error = err;
+ complete(&info->fw_completion);
+ return;
+ }
+ }
+
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ NBT_DBG_FW("Sending firmware\n");
+
+ time = jiffies;
+
+ info->fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ NBT_DBG_FW("Sending commands\n");
+
+ /*
+ * Disable smart-idle as UART TX interrupts
+ * are not wake-up capable
+ */
+ hci_h4p_smart_idle(info, 0);
+
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(2000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ NBT_DBG_FW("Firmware sent in %d msecs\n",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-csr.c b/drivers/bluetooth/hci_h4p/fw-csr.c
new file mode 100644
index 0000000..020fa52
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-csr.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2008 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ /* Check if this is fw packet */
+ if (skb->data[0] != 0xff) {
+ hci_recv_frame(info->hdev, skb);
+ return;
+ }
+
+ if (skb->data[11] || skb->data[12]) {
+ dev_err(info->dev, "Firmware sending command failed\n");
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+ complete(&info->fw_completion);
+}
+
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ static const u8 nokia_oui[3] = {0x00, 0x19, 0x4F};
+ struct sk_buff *skb;
+ unsigned int offset;
+ int retries, count, i, not_valid;
+ unsigned long flags;
+
+ info->fw_error = 0;
+
+ NBT_DBG_FW("Sending firmware\n");
+ skb = skb_dequeue(fw_queue);
+
+ if (!skb)
+ return -ENOMSG;
+
+ /* Check if this is bd_address packet */
+ if (skb->data[15] == 0x01 && skb->data[16] == 0x00) {
+ offset = 21;
+ skb->data[offset + 1] = 0x00;
+ skb->data[offset + 5] = 0x00;
+
+ not_valid = 1;
+ for (i = 0; i < 6; i++) {
+ if (info->bd_addr[i] != 0x00) {
+ not_valid = 0;
+ break;
+ }
+ }
+
+ if (not_valid) {
+ dev_info(info->dev, "Valid bluetooth address not found,"
+ " setting some random\n");
+ /* When address is not valid, use some random */
+ memcpy(info->bd_addr, nokia_oui, 3);
+ get_random_bytes(info->bd_addr + 3, 3);
+ }
+
+ skb->data[offset + 7] = info->bd_addr[0];
+ skb->data[offset + 6] = info->bd_addr[1];
+ skb->data[offset + 4] = info->bd_addr[2];
+ skb->data[offset + 0] = info->bd_addr[3];
+ skb->data[offset + 3] = info->bd_addr[4];
+ skb->data[offset + 2] = info->bd_addr[5];
+ }
+
+ for (count = 1; ; count++) {
+ NBT_DBG_FW("Sending firmware command %d\n", count);
+ init_completion(&info->fw_completion);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ break;
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(1000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+ };
+
+ /* Wait for chip warm reset */
+ retries = 100;
+ while ((!skb_queue_empty(&info->txq) ||
+ !(hci_h4p_inb(info, UART_LSR) & UART_LSR_TEMT)) &&
+ retries--) {
+ msleep(10);
+ }
+ if (!retries) {
+ dev_err(info->dev, "Transmitter not empty\n");
+ return -ETIMEDOUT;
+ }
+
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev, "cts didn't deassert after final speed\n");
+ return -ETIMEDOUT;
+ }
+
+ retries = 100;
+ do {
+ init_completion(&info->init_completion);
+ hci_h4p_send_alive_packet(info);
+ retries--;
+ } while (!wait_for_completion_timeout(&info->init_completion, 100) &&
+ retries > 0);
+
+ if (!retries) {
+ dev_err(info->dev, "No alive reply after speed change\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw-ti1273.c b/drivers/bluetooth/hci_h4p/fw-ti1273.c
new file mode 100644
index 0000000..d46c3a0
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw-ti1273.c
@@ -0,0 +1,113 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/serial_reg.h>
+
+#include "hci_h4p.h"
+
+static struct sk_buff_head *fw_q;
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb)
+{
+ struct sk_buff *fw_skb;
+ unsigned long flags;
+
+ if (skb->data[5] != 0x00) {
+ dev_err(info->dev, "Firmware sending command failed 0x%.2x\n",
+ skb->data[5]);
+ info->fw_error = -EPROTO;
+ }
+
+ kfree_skb(skb);
+
+ fw_skb = skb_dequeue(fw_q);
+ if (fw_skb == NULL || info->fw_error) {
+ complete(&info->fw_completion);
+ return;
+ }
+
+ hci_h4p_enable_tx(info);
+ skb_queue_tail(&info->txq, fw_skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue)
+{
+ struct sk_buff *skb;
+ unsigned long flags, time;
+
+ info->fw_error = 0;
+
+ NBT_DBG_FW("Sending firmware\n");
+
+ time = jiffies;
+
+ fw_q = fw_queue;
+ skb = skb_dequeue(fw_queue);
+ if (!skb)
+ return -ENODATA;
+
+ NBT_DBG_FW("Sending commands\n");
+ /* Check if this is bd_address packet */
+ init_completion(&info->fw_completion);
+ hci_h4p_enable_tx(info);
+ skb_queue_tail(&info->txq, skb);
+ spin_lock_irqsave(&info->lock, flags);
+ hci_h4p_outb(info, UART_IER, hci_h4p_inb(info, UART_IER) |
+ UART_IER_THRI);
+ spin_unlock_irqrestore(&info->lock, flags);
+
+ if (!wait_for_completion_timeout(&info->fw_completion,
+ msecs_to_jiffies(40000))) {
+ dev_err(info->dev, "No reply to fw command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (info->fw_error) {
+ dev_err(info->dev, "FW error\n");
+ return -EPROTO;
+ }
+
+ NBT_DBG_FW("Firmware sent in %d msecs\n",
+ jiffies_to_msecs(jiffies-time));
+
+ hci_h4p_set_auto_ctsrts(info, 0, UART_EFR_RTS);
+ hci_h4p_set_rts(info, 0);
+ hci_h4p_change_speed(info, BC4_MAX_BAUD_RATE);
+ if (hci_h4p_wait_for_cts(info, 1, 100)) {
+ dev_err(info->dev,
+ "cts didn't go down after final speed change\n");
+ return -ETIMEDOUT;
+ }
+ hci_h4p_set_auto_ctsrts(info, 1, UART_EFR_RTS);
+
+ return 0;
+}
diff --git a/drivers/bluetooth/hci_h4p/fw.c b/drivers/bluetooth/hci_h4p/fw.c
new file mode 100644
index 0000000..b767a12
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/fw.c
@@ -0,0 +1,166 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/clk.h>
+
+#include <net/bluetooth/bluetooth.h>
+
+#include "hci_h4p.h"
+
+static int fw_pos;
+
+/* Firmware handling */
+static int hci_h4p_open_firmware(struct hci_h4p_info *info,
+ const struct firmware **fw_entry)
+{
+ int err;
+
+ fw_pos = 0;
+ NBT_DBG_FW("Opening %d/%d firmware\n", info->man_id, info->ver_id);
+ switch (info->man_id) {
+ case BT_CHIP_TI:
+ err = request_firmware(fw_entry, FW_NAME_TI, info->dev);
+ break;
+ case BT_CHIP_CSR:
+ err = request_firmware(fw_entry, FW_NAME_CSR, info->dev);
+ break;
+ case BT_CHIP_BCM:
+ err = request_firmware(fw_entry, FW_NAME_BCM, info->dev);
+ break;
+ default:
+ dev_err(info->dev, "Invalid chip type %d\n", info->man_id);
+ *fw_entry = NULL;
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static void hci_h4p_close_firmware(const struct firmware *fw_entry)
+{
+ release_firmware(fw_entry);
+}
+
+/* Read fw. Return length of the command. If no more commands in
+ * fw 0 is returned. In error case return value is negative.
+ */
+static int hci_h4p_read_fw_cmd(struct hci_h4p_info *info, struct sk_buff **skb,
+ const struct firmware *fw_entry, gfp_t how)
+{
+ unsigned int cmd_len;
+
+ if (fw_pos >= fw_entry->size)
+ return 0;
+
+ if (fw_pos + 2 > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 1\n");
+ return -EMSGSIZE;
+ }
+
+ cmd_len = fw_entry->data[fw_pos++];
+ cmd_len += fw_entry->data[fw_pos++] << 8;
+ if (cmd_len == 0)
+ return 0;
+
+ if (fw_pos + cmd_len > fw_entry->size) {
+ dev_err(info->dev, "Corrupted firmware image 2\n");
+ return -EMSGSIZE;
+ }
+
+ *skb = bt_skb_alloc(cmd_len, how);
+ if (!*skb) {
+ dev_err(info->dev, "Cannot reserve memory for buffer\n");
+ return -ENOMEM;
+ }
+ memcpy(skb_put(*skb, cmd_len), &fw_entry->data[fw_pos], cmd_len);
+
+ fw_pos += cmd_len;
+
+ return (*skb)->len;
+}
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ const struct firmware *fw_entry = NULL;
+ struct sk_buff *skb = NULL;
+ int err;
+
+ err = hci_h4p_open_firmware(info, &fw_entry);
+ if (err < 0 || !fw_entry)
+ goto err_clean;
+
+ while ((err = hci_h4p_read_fw_cmd(info, &skb, fw_entry, GFP_KERNEL))) {
+ if (err < 0 || !skb)
+ goto err_clean;
+
+ skb_queue_tail(fw_queue, skb);
+ }
+
+err_clean:
+ hci_h4p_close_firmware(fw_entry);
+ return err;
+}
+
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue)
+{
+ int err;
+
+ switch (info->man_id) {
+ case BT_CHIP_CSR:
+ err = hci_h4p_bc4_send_fw(info, fw_queue);
+ break;
+ case BT_CHIP_TI:
+ err = hci_h4p_ti1273_send_fw(info, fw_queue);
+ break;
+ case BT_CHIP_BCM:
+ err = hci_h4p_bcm_send_fw(info, fw_queue);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to send firmware\n");
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb)
+{
+ switch (info->man_id) {
+ case BT_CHIP_CSR:
+ hci_h4p_bc4_parse_fw_event(info, skb);
+ break;
+ case BT_CHIP_TI:
+ hci_h4p_ti1273_parse_fw_event(info, skb);
+ break;
+ case BT_CHIP_BCM:
+ hci_h4p_bcm_parse_fw_event(info, skb);
+ break;
+ default:
+ dev_err(info->dev, "Don't know how to parse fw event\n");
+ info->fw_error = -EINVAL;
+ }
+
+ return;
+}
diff --git a/drivers/bluetooth/hci_h4p/hci_h4p.h b/drivers/bluetooth/hci_h4p/hci_h4p.h
new file mode 100644
index 0000000..ebafd37
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/hci_h4p.h
@@ -0,0 +1,238 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005-2010 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+#ifndef __DRIVERS_BLUETOOTH_HCI_H4P_H
+#define __DRIVERS_BLUETOOTH_HCI_H4P_H
+
+#define BT_CHIP_CSR 0x02
+#define BT_CHIP_TI 0x30
+#define BT_CHIP_BCM 0x04
+
+#define FW_NAME_CSR "bc4fw.bin"
+#define FW_NAME_TI "ti1273.bin"
+#define FW_NAME_BCM "bcmfw.bin"
+
+#define UART_SYSC_OMAP_RESET 0x03
+#define UART_SYSS_RESETDONE 0x01
+#define UART_OMAP_SCR_EMPTY_THR 0x08
+#define UART_OMAP_SCR_WAKEUP 0x10
+#define UART_OMAP_SSR_WAKEUP 0x02
+#define UART_OMAP_SSR_TXFULL 0x01
+
+#define UART_OMAP_SYSC_IDLEMODE 0x03
+#define UART_OMAP_SYSC_IDLEMASK (3 << UART_OMAP_SYSC_IDLEMODE)
+
+#define UART_OMAP_SYSC_FORCE_IDLE (0 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_NO_IDLE (1 << UART_OMAP_SYSC_IDLEMODE)
+#define UART_OMAP_SYSC_SMART_IDLE (2 << UART_OMAP_SYSC_IDLEMODE)
+
+#define NBT_DBG(fmt, arg...) \
+ pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_FW(fmt, arg...) \
+ pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_POWER(fmt, arg...) \
+ pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER(fmt, arg...) \
+ pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+#define NBT_DBG_TRANSFER_NF(fmt, arg...) \
+ pr_debug(fmt "" , ## arg)
+
+#define NBT_DBG_DMA(fmt, arg...) \
+ pr_debug("%s: " fmt "" , __func__ , ## arg)
+
+struct hci_h4p_info {
+ struct hci_dev *hdev;
+ spinlock_t lock;
+
+ void __iomem *uart_base;
+ unsigned long uart_phys_base;
+ int irq;
+ struct device *dev;
+ u8 chip_type;
+ void (*bt_wakeup)(bool enable);
+ bool (*host_wakeup)(void);
+ void (*reset)(bool enable);
+ int host_wakeup_gpio;
+ int man_id;
+ int ver_id;
+
+ struct sk_buff_head fw_queue;
+ struct completion init_completion;
+ struct completion fw_completion;
+ int fw_error;
+ int init_error;
+
+ struct sk_buff_head txq;
+
+ struct sk_buff *rx_skb;
+ long rx_count;
+ unsigned long rx_state;
+ unsigned long garbage_bytes;
+
+ u8 bd_addr[6];
+ struct sk_buff_head *fw_q;
+
+ int pm_enabled;
+ int tx_enabled;
+ int autorts;
+ int rx_enabled;
+
+ int tx_clocks_en;
+ int rx_clocks_en;
+ spinlock_t clocks_lock;
+ struct clk *uart_iclk;
+ struct clk *uart_fclk;
+ atomic_t clk_users;
+ u16 dll;
+ u16 dlh;
+ u16 ier;
+ u16 mdr1;
+ u16 efr;
+};
+
+struct hci_h4p_radio_hdr {
+ __u8 evt;
+ __u8 dlen;
+} __attribute__ ((packed));
+
+
+struct hci_h4p_init_hdr {
+ __u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_HDR_SIZE 1
+
+struct hci_h4p_init_cmd {
+ __u8 ack;
+ __u16 baudrate;
+ __u16 unused;
+ __u8 mode;
+ __u16 sys_clk;
+ __u16 unused2;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_CMD_SIZE 10
+
+struct hci_h4p_init_evt {
+ __u8 ack;
+ __u16 baudrate;
+ __u16 unused;
+ __u8 mode;
+ __u16 sys_clk;
+ __u16 unused2;
+ __u8 man_id;
+ __u8 ver_id;
+} __attribute__ ((packed));
+#define HCI_H4P_INIT_EVT_SIZE 12
+
+struct hci_h4p_alive_hdr {
+ __u8 dlen;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_HDR_SIZE 1
+
+struct hci_h4p_alive_msg {
+ __u8 message_id;
+ __u8 unused;
+} __attribute__ ((packed));
+#define HCI_H4P_ALIVE_MSG_SIZE 2
+
+#define MAX_BAUD_RATE 921600
+#define BC4_MAX_BAUD_RATE 3692300
+#define UART_CLOCK 48000000
+#define BT_INIT_DIVIDER 320
+#define BT_BAUDRATE_DIVIDER 384000000
+#define BT_SYSCLK_DIV 1000
+#define INIT_SPEED 120000
+
+#define HCI_H4P_MODE 0x4c
+
+#define HCI_H4P_ACK 0x20
+#define HCI_H4P_NACK 0x40
+#define HCI_H4P_ALIVE_IND_REQ 0x55
+#define HCI_H4P_ALIVE_IND_RESP 0xCC
+
+#define H4_TYPE_SIZE 1
+#define H4_RADIO_HDR_SIZE 2
+
+/* H4+ packet types */
+#define H4_CMD_PKT 0x01
+#define H4_ACL_PKT 0x02
+#define H4_SCO_PKT 0x03
+#define H4_EVT_PKT 0x04
+#define H4_NEG_PKT 0x06
+#define H4_ALIVE_PKT 0x07
+#define H4_RADIO_PKT 0x08
+
+/* TX states */
+#define WAIT_FOR_PKT_TYPE 1
+#define WAIT_FOR_HEADER 2
+#define WAIT_FOR_DATA 3
+
+struct hci_fw_event {
+ struct hci_event_hdr hev;
+ struct hci_ev_cmd_complete cmd;
+ u8 status;
+} __attribute__ ((packed));
+
+int hci_h4p_send_alive_packet(struct hci_h4p_info *info);
+
+void hci_h4p_bcm_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bcm_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_bc4_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_bc4_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+void hci_h4p_ti1273_parse_fw_event(struct hci_h4p_info *info,
+ struct sk_buff *skb);
+int hci_h4p_ti1273_send_fw(struct hci_h4p_info *info,
+ struct sk_buff_head *fw_queue);
+
+int hci_h4p_read_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+int hci_h4p_send_fw(struct hci_h4p_info *info, struct sk_buff_head *fw_queue);
+void hci_h4p_parse_fw_event(struct hci_h4p_info *info, struct sk_buff *skb);
+
+void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val);
+u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset);
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active);
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active, int timeout_ms);
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which);
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed);
+int hci_h4p_reset_uart(struct hci_h4p_info *info);
+void hci_h4p_init_uart(struct hci_h4p_info *info);
+void hci_h4p_enable_tx(struct hci_h4p_info *info);
+void hci_h4p_store_regs(struct hci_h4p_info *info);
+void hci_h4p_restore_regs(struct hci_h4p_info *info);
+void hci_h4p_smart_idle(struct hci_h4p_info *info, bool enable);
+
+#endif /* __DRIVERS_BLUETOOTH_HCI_H4P_H */
diff --git a/drivers/bluetooth/hci_h4p/uart.c b/drivers/bluetooth/hci_h4p/uart.c
new file mode 100644
index 0000000..033825f
--- /dev/null
+++ b/drivers/bluetooth/hci_h4p/uart.c
@@ -0,0 +1,203 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2005, 2006 Nokia Corporation.
+ *
+ * Contact: Ville Tervo <ville.tervo@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/serial_reg.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <linux/io.h>
+
+#include "hci_h4p.h"
+
+inline void hci_h4p_outb(struct hci_h4p_info *info, unsigned int offset, u8 val)
+{
+ __raw_writeb(val, info->uart_base + (offset << 2));
+}
+
+inline u8 hci_h4p_inb(struct hci_h4p_info *info, unsigned int offset)
+{
+ return __raw_readb(info->uart_base + (offset << 2));
+}
+
+void hci_h4p_set_rts(struct hci_h4p_info *info, int active)
+{
+ u8 b;
+
+ b = hci_h4p_inb(info, UART_MCR);
+ if (active)
+ b |= UART_MCR_RTS;
+ else
+ b &= ~UART_MCR_RTS;
+ hci_h4p_outb(info, UART_MCR, b);
+}
+
+int hci_h4p_wait_for_cts(struct hci_h4p_info *info, int active,
+ int timeout_ms)
+{
+ unsigned long timeout;
+ int state;
+
+ timeout = jiffies + msecs_to_jiffies(timeout_ms);
+ for (;;) {
+ state = hci_h4p_inb(info, UART_MSR) & UART_MSR_CTS;
+ if (active) {
+ if (state)
+ return 0;
+ } else {
+ if (!state)
+ return 0;
+ }
+ if (time_after(jiffies, timeout))
+ return -ETIMEDOUT;
+ msleep(1);
+ }
+}
+
+void __hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ u8 lcr, b;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ b = hci_h4p_inb(info, UART_EFR);
+ if (on)
+ b |= which;
+ else
+ b &= ~which;
+ hci_h4p_outb(info, UART_EFR, b);
+ hci_h4p_outb(info, UART_LCR, lcr);
+}
+
+void hci_h4p_set_auto_ctsrts(struct hci_h4p_info *info, int on, u8 which)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&info->lock, flags);
+ __hci_h4p_set_auto_ctsrts(info, on, which);
+ spin_unlock_irqrestore(&info->lock, flags);
+}
+
+void hci_h4p_change_speed(struct hci_h4p_info *info, unsigned long speed)
+{
+ unsigned int divisor;
+ u8 lcr, mdr1;
+
+ NBT_DBG("Setting speed %lu\n", speed);
+
+ if (speed >= 460800) {
+ divisor = UART_CLOCK / 13 / speed;
+ mdr1 = 3;
+ } else {
+ divisor = UART_CLOCK / 16 / speed;
+ mdr1 = 0;
+ }
+
+ /* Make sure UART mode is disabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB); /* Set DLAB */
+ hci_h4p_outb(info, UART_DLL, divisor & 0xff); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, divisor >> 8);
+ hci_h4p_outb(info, UART_LCR, lcr);
+
+ /* Make sure UART mode is enabled */
+ hci_h4p_outb(info, UART_OMAP_MDR1, mdr1);
+}
+
+int hci_h4p_reset_uart(struct hci_h4p_info *info)
+{
+ int count = 0;
+
+ /* Reset the UART */
+ hci_h4p_outb(info, UART_OMAP_SYSC, UART_SYSC_OMAP_RESET);
+ while (!(hci_h4p_inb(info, UART_OMAP_SYSS) & UART_SYSS_RESETDONE)) {
+ if (count++ > 100) {
+ dev_err(info->dev, "hci_h4p: UART reset timeout\n");
+ return -ENODEV;
+ }
+ udelay(1);
+ }
+
+ return 0;
+}
+
+
+void hci_h4p_store_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ info->dll = hci_h4p_inb(info, UART_DLL);
+ info->dlh = hci_h4p_inb(info, UART_DLM);
+ info->efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ info->mdr1 = hci_h4p_inb(info, UART_OMAP_MDR1);
+ info->ier = hci_h4p_inb(info, UART_IER);
+}
+
+void hci_h4p_restore_regs(struct hci_h4p_info *info)
+{
+ u16 lcr = 0;
+
+ hci_h4p_init_uart(info);
+
+ hci_h4p_outb(info, UART_OMAP_MDR1, 7);
+ lcr = hci_h4p_inb(info, UART_LCR);
+ hci_h4p_outb(info, UART_LCR, 0xBF);
+ hci_h4p_outb(info, UART_DLL, info->dll); /* Set speed */
+ hci_h4p_outb(info, UART_DLM, info->dlh);
+ hci_h4p_outb(info, UART_EFR, info->efr);
+ hci_h4p_outb(info, UART_LCR, lcr);
+ hci_h4p_outb(info, UART_OMAP_MDR1, info->mdr1);
+ hci_h4p_outb(info, UART_IER, info->ier);
+}
+
+void hci_h4p_init_uart(struct hci_h4p_info *info)
+{
+ u8 mcr, efr;
+
+ /* Enable and setup FIFO */
+ hci_h4p_outb(info, UART_OMAP_MDR1, 0x00);
+
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ efr = hci_h4p_inb(info, UART_EFR);
+ hci_h4p_outb(info, UART_EFR, UART_EFR_ECB);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ mcr = hci_h4p_inb(info, UART_MCR);
+ hci_h4p_outb(info, UART_MCR, UART_MCR_TCRTLR);
+ hci_h4p_outb(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT |
+ (3 << 6) | (0 << 4));
+ hci_h4p_outb(info, UART_LCR, 0xbf);
+ hci_h4p_outb(info, UART_TI752_TLR, 0xed);
+ hci_h4p_outb(info, UART_TI752_TCR, 0xef);
+ hci_h4p_outb(info, UART_EFR, efr);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_DLAB);
+ hci_h4p_outb(info, UART_MCR, 0x00);
+ hci_h4p_outb(info, UART_LCR, UART_LCR_WLEN8);
+ hci_h4p_outb(info, UART_IER, UART_IER_RDI | UART_IER_RLSI);
+ hci_h4p_outb(info, UART_OMAP_WER, 0xff);
+ hci_h4p_outb(info, UART_OMAP_SYSC, (0 << 0) | (1 << 2) | (1 << 3));
+}
diff --git a/include/linux/bluetooth/hci_h4p.h b/include/linux/bluetooth/hci_h4p.h
new file mode 100644
index 0000000..ba1d764
--- /dev/null
+++ b/include/linux/bluetooth/hci_h4p.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of hci_h4p bluetooth driver
+ *
+ * Copyright (C) 2010 Nokia Corporation.
+ *
+ * Contact: Roger Quadros <roger.quadros@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+
+/**
+ * struct hci_h4p_platform data - hci_h4p Platform data structure
+ * @uart_base: UART base address
+ * @uart_irq: UART Interrupt number
+ * @host_wu: Function hook determine if Host should wakeup or not.
+ * @bt_wu: Function hook to enable/disable Bluetooth transmission
+ * @reset: Function hook to set/clear reset conditiona
+ * @host_wu_gpio: Gpio used to wakeup host
+ */
+struct hci_h4p_platform_data {
+ void *uart_base;
+ unsigned int uart_irq;
+ bool (*host_wu)(void);
+ void (*bt_wu)(bool);
+ void (*reset)(bool);
+ unsigned int host_wu_gpio;
+};
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related
* [PATCH 1/2] Bluetooth: Use hcon directly instead of conn->hcon where possible
From: Marcel Holtmann @ 2013-10-18 10:43 UTC (permalink / raw)
To: linux-bluetooth
When the HCI connection hcon is already dereferenced, then use hcon
directly instead of conn->hcon.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap_core.c | 7 +++----
net/bluetooth/smp.c | 2 +-
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 763b741..9757297 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -6399,8 +6399,7 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
if (hcon->type != ACL_LINK)
goto drop;
- chan = l2cap_global_chan_by_psm(0, psm, &conn->hcon->src,
- &conn->hcon->dst);
+ chan = l2cap_global_chan_by_psm(0, psm, &hcon->src, &hcon->dst);
if (!chan)
goto drop;
@@ -6413,7 +6412,7 @@ static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm,
goto drop;
/* Store remote BD_ADDR and PSM for msg_name */
- bacpy(&bt_cb(skb)->bdaddr, &conn->hcon->dst);
+ bacpy(&bt_cb(skb)->bdaddr, &hcon->dst);
bt_cb(skb)->psm = psm;
if (!chan->ops->recv(chan, skb))
@@ -6433,7 +6432,7 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
goto drop;
chan = l2cap_global_chan_by_scid(BT_CONNECTED, L2CAP_CID_ATT,
- &conn->hcon->src, &conn->hcon->dst);
+ &hcon->src, &hcon->dst);
if (!chan)
goto drop;
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index fc200e0..85a2796c 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -864,7 +864,7 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
return -EILSEQ;
}
- if (!test_bit(HCI_LE_ENABLED, &conn->hcon->hdev->dev_flags)) {
+ if (!test_bit(HCI_LE_ENABLED, &hcon->hdev->dev_flags)) {
err = -ENOTSUPP;
reason = SMP_PAIRING_NOTSUPP;
goto done;
--
1.8.3.1
^ permalink raw reply related
* [PATCH 2/2] Bluetooth: Block ATT connection on LE when device is blocked
From: Marcel Holtmann @ 2013-10-18 10:43 UTC (permalink / raw)
To: linux-bluetooth
When the remote LE device is blocked, then do not create a L2CAP
channel for it. Without a channel, all packets for that connection
will be dropped.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/l2cap_core.c | 21 ++++++++++++++++-----
1 file changed, 16 insertions(+), 5 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9757297..bf1f34e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1382,14 +1382,16 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid,
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
+ struct hci_conn *hcon = conn->hcon;
struct sock *parent;
struct l2cap_chan *chan, *pchan;
+ __u8 dst_type;
BT_DBG("");
/* Check if we have socket listening on cid */
pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
- &conn->hcon->src, &conn->hcon->dst);
+ &hcon->src, &hcon->dst);
if (!pchan)
return;
@@ -1397,6 +1399,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
if (__l2cap_get_chan_by_dcid(conn, L2CAP_CID_ATT))
return;
+ dst_type = bdaddr_type(hcon, hcon->dst_type);
+
+ /* If device is blocked, do not create a channel for it */
+ if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, dst_type))
+ return;
+
parent = pchan->sk;
lock_sock(parent);
@@ -1407,10 +1415,10 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
chan->dcid = L2CAP_CID_ATT;
- bacpy(&chan->src, &conn->hcon->src);
- bacpy(&chan->dst, &conn->hcon->dst);
- chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
- chan->dst_type = bdaddr_type(conn->hcon, conn->hcon->dst_type);
+ bacpy(&chan->src, &hcon->src);
+ bacpy(&chan->dst, &hcon->dst);
+ chan->src_type = bdaddr_type(hcon, hcon->src_type);
+ chan->dst_type = dst_type;
__l2cap_chan_add(conn, chan);
@@ -6438,6 +6446,9 @@ static void l2cap_att_channel(struct l2cap_conn *conn,
BT_DBG("chan %p, len %d", chan, skb->len);
+ if (hci_blacklist_lookup(hcon->hdev, &hcon->dst, hcon->dst_type))
+ goto drop;
+
if (chan->imtu < skb->len)
goto drop;
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCHv5 0/7] Android BlueZ patches, second chunk
From: Johan Hedberg @ 2013-10-18 11:36 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381998406-16662-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Thu, Oct 17, 2013, Andrei Emeltchenko wrote:
> This is second chunk from my initial big patch set. Fixed style issues
> commented by Marcel.
>
> Changes:
> * v5: Rebased against upstream, hid and pan now uses explicit struct initialization,
> adapter-related functionality moved to adapter.c, fixed issues reported by Johan.
> * v4: Fixes several typos and missing style issues commented by Marcel earlier.
> * v3: Following upstream comments file names are changed from "_" to "-", added kernel style
> struct initialization, fixed bug checking status for mgmt commands, added 2 HALs skeletons.
> * v2: Corrected android_daemon -> enable_android autoconf stuff, better name for acquiring caps,
> renamed hal_msg.h to hal-msg.h due to Johan's comment. Added small test-sdp fix.
>
> Note that due to Marcel comment this cannot be built unless you include my patch
> for Android bionic library:
> http://code.google.com/p/android-bluez/source/detail?r=77a07e7703b63e280d9880baad30b3375e7df079&repo=bionic#
>
> Andrei Emeltchenko (7):
> android: Add capabilities and set userid
> android: Implement read_info_complete callback
> android: Use kernel style to initialize struct fields
> android: Rename hal_bluetooth.c to hal-bluetooth.c
> android: Rename hal_bt_sock.c to hal-bt-sock.c
> android: Add HID Host skeleton
> android: Add PAN skeleton
>
> Makefile.android | 3 +-
> android/Android.mk | 7 +-
> android/adapter.c | 108 +++++++++++--
> android/hal-bluetooth.c | 392 +++++++++++++++++++++++++++++++++++++++++++++++
> android/hal-bt-sock.c | 85 ++++++++++
> android/hal-hidhost.c | 204 ++++++++++++++++++++++++
> android/hal-pan.c | 120 +++++++++++++++
> android/hal.h | 2 +
> android/hal_bluetooth.c | 384 ----------------------------------------------
> android/hal_bt_sock.c | 85 ----------
> android/main.c | 77 ++++++++--
> configure.ac | 4 +
> 12 files changed, 980 insertions(+), 491 deletions(-)
> create mode 100644 android/hal-bluetooth.c
> create mode 100644 android/hal-bt-sock.c
> create mode 100644 android/hal-hidhost.c
> create mode 100644 android/hal-pan.c
> delete mode 100644 android/hal_bluetooth.c
> delete mode 100644 android/hal_bt_sock.c
After quite heavy fixing and additional patches of my own, these are now
upstream.
Johan
^ permalink raw reply
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