* Re: [GSoC'10] : New Command Line Tool(s) for bluez
From: Bastien Nocera @ 2010-08-16 9:40 UTC (permalink / raw)
To: Alexander Orlenko; +Cc: Andrei Emeltchenko, linux-bluetooth
In-Reply-To: <AANLkTimW1SmfZ+j=F7kTSwosdz=kh+g9ofcqdTeGE7CB@mail.gmail.com>
On Mon, 2010-08-16 at 10:24 +1100, Alexander Orlenko wrote:
> Hi everyone,
>
> I updated project info page at http://hostisdown.org/gsoc/projects/bluez-tools
> Created project home page: http://code.google.com/p/bluez-tools
> Current release available for download: 0.1.18-6432
>
> Code of my project does not based on non-GTK parts of
> libgnome-bluetooth. I wrote glib gobjects for all bluez dbus
> interfaces.
Shame, but I won't hold you against that :)
> I will continue developing my project after end of GSoC.
Hopefully people will package it for distributions so we don't get as
many requests for command-line pairing agents :)
Cheers
^ permalink raw reply
* Re: [GSoC'10] : New Command Line Tool(s) for bluez
From: Alexander Orlenko @ 2010-08-15 23:24 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: Bastien Nocera, linux-bluetooth
In-Reply-To: <AANLkTik3d0rY2QNrhevwzPz28VQwKuj7A5s-9l152H4Y@mail.gmail.com>
Hi everyone,
I updated project info page at http://hostisdown.org/gsoc/projects/bluez-tools
Created project home page: http://code.google.com/p/bluez-tools
Current release available for download: 0.1.18-6432
Code of my project does not based on non-GTK parts of
libgnome-bluetooth. I wrote glib gobjects for all bluez dbus
interfaces.
I will continue developing my project after end of GSoC.
On 21 May 2010 18:29, Andrei Emeltchenko
<andrei.emeltchenko.news@gmail.com> wrote:
>
> On Thu, May 20, 2010 at 4:08 PM, Bastien Nocera <hadess@hadess.net> wrote:
> > On Fri, 2010-05-21 at 00:04 +1100, Alexander Orlenko wrote:
> >> Hi everyone,
> >>
> >> My name is Alexander Orlenko, I am a GSoC student of this year. I am
> >> doing a project "bluez-tools",
> >> http://hostisdown.org/gsoc/projects/bluez-tools (a little more info
> >> about the project). I need some feedback about what approach should I
> >> take.
> >
> > I'm not sure whether you'd be interested, but you could base your code
> > on the non-GTK parts of libgnome-bluetooth, which already implements a
> > number of those things, and would just need to be wrapped up.
>
> There is also python code in bluez/test repository.
>
> -- Andrei
>
> >
> > Cheers
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at http://vger.kernel.org/majordomo-info.html
> >
^ permalink raw reply
* Re: [PATCH] Bluetooth: Fix inconsistent lock state with RFCOMM
From: Marcel Holtmann @ 2010-08-14 19:39 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: linux-bluetooth, Gustavo F. Padovan
In-Reply-To: <1281797213-10940-1-git-send-email-gustavo@padovan.org>
Hi Gustavo,
> When receiving a rfcomm connection with the old dund deamon the following
> inconsistent lock state happens:
>
> [ 811.702999] =================================
> [ 811.702999] [ INFO: inconsistent lock state ]
> [ 811.702999] 2.6.35-rc1-01743-g41069ad-dirty #1
> [ 811.702999] ---------------------------------
> [ 811.702999] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
> [ 811.702999] krfcommd/3892 [HC0[0]:SC0[0]:HE1:SE1] takes:
> [ 811.702999] (slock-AF_BLUETOOTH){+.?...}, at: [<ffffffffa0189b56>] rfcomm_sk_state_change+0x46/0x170 [rfcomm]
> [ 811.702999] {IN-SOFTIRQ-W} state was registered at:
> [ 811.702999] [<ffffffff8108dfa6>] __lock_acquire+0x5b6/0x1560
> [ 811.702999] [<ffffffff8108efaa>] lock_acquire+0x5a/0x70
> [ 811.702999] [<ffffffff81387b2c>] _raw_spin_lock+0x2c/0x40
> [ 811.702999] [<ffffffffa0043092>] 0xffffffffa0043092
> [ 811.702999] [<ffffffffa0044a3f>] 0xffffffffa0044a3f
> [ 811.702999] [<ffffffffa0047183>] 0xffffffffa0047183
> [ 811.702999] [<ffffffffa004798b>] 0xffffffffa004798b
> [ 811.702999] [<ffffffffa000db4b>] 0xffffffffa000db4b
> [ 811.702999] [<ffffffff81067efb>] tasklet_action+0xcb/0xe0
> [ 811.702999] [<ffffffff810685ee>] __do_softirq+0xae/0x150
> [ 811.702999] [<ffffffff81029c0c>] call_softirq+0x1c/0x30
> [ 811.702999] [<ffffffff8102bd75>] do_softirq+0x75/0xb0
> [ 811.702999] [<ffffffff8106823d>] irq_exit+0x8d/0xa0
> [ 811.702999] [<ffffffff8102b330>] do_IRQ+0x70/0xf0
> [ 811.702999] [<ffffffff81388513>] ret_from_intr+0x0/0xf
> [ 811.702999] [<ffffffff81027dfa>] cpu_idle+0x5a/0xb0
> [ 811.702999] [<ffffffff81382934>] start_secondary+0x211/0x254
> [ 811.702999] irq event stamp: 411
> [ 811.702999] hardirqs last enabled at (411): [<ffffffff81068432>] local_bh_enable_ip+0x82/0xe0
> [ 811.702999] hardirqs last disabled at (409): [<ffffffff8106860e>] __do_softirq+0xce/0x150
> [ 811.702999] softirqs last enabled at (410): [<ffffffff8106863e>] __do_softirq+0xfe/0x150
> [ 811.702999] softirqs last disabled at (391): [<ffffffff81029c0c>] call_softirq+0x1c/0x30
> [ 811.702999]
> [ 811.702999] other info that might help us debug this:
> [ 811.702999] 2 locks held by krfcommd/3892:
> [ 811.702999] #0: (rfcomm_mutex){+.+.+.}, at: [<ffffffffa0188744>] rfcomm_run+0x174/0xb20 [rfcomm]
> [ 811.702999] #1: (&(&d->lock)->rlock){+.+...}, at: [<ffffffffa0186223>] rfcomm_dlc_accept+0x53/0x100 [rfcomm]
> [ 811.702999]
> [ 811.702999] stack backtrace:
> [ 811.702999] Pid: 3892, comm: krfcommd Tainted: G W 2.6.35-rc1-01743-g41069ad-dirty #1
> [ 811.702999] Call Trace:
> [ 811.702999] [<ffffffff8108c541>] print_usage_bug+0x171/0x180
> [ 811.702999] [<ffffffff8108d323>] mark_lock+0x333/0x400
> [ 811.702999] [<ffffffff8108e02a>] __lock_acquire+0x63a/0x1560
> [ 811.702999] [<ffffffff8108e515>] ? __lock_acquire+0xb25/0x1560
> [ 811.702999] [<ffffffff8108efaa>] lock_acquire+0x5a/0x70
> [ 811.702999] [<ffffffffa0189b56>] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm]
> [ 811.702999] [<ffffffff81387b2c>] _raw_spin_lock+0x2c/0x40
> [ 811.702999] [<ffffffffa0189b56>] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm]
> [ 811.702999] [<ffffffffa0189b56>] rfcomm_sk_state_change+0x46/0x170 [rfcomm]
> [ 811.702999] [<ffffffffa0186239>] rfcomm_dlc_accept+0x69/0x100 [rfcomm]
> [ 811.702999] [<ffffffffa0186a49>] rfcomm_check_accept+0x59/0xd0 [rfcomm]
> [ 811.702999] [<ffffffffa0187cab>] rfcomm_recv_frame+0x9fb/0x1320 [rfcomm]
> [ 811.702999] [<ffffffff8138827b>] ? _raw_spin_unlock_irqrestore+0x3b/0x60
> [ 811.702999] [<ffffffff8108d72d>] ? trace_hardirqs_on_caller+0x13d/0x180
> [ 811.702999] [<ffffffff8108d77d>] ? trace_hardirqs_on+0xd/0x10
> [ 811.702999] [<ffffffffa01887f1>] rfcomm_run+0x221/0xb20 [rfcomm]
> [ 811.702999] [<ffffffff81385667>] ? schedule+0x267/0x5d0
> [ 811.702999] [<ffffffffa01885d0>] ? rfcomm_run+0x0/0xb20 [rfcomm]
> [ 811.702999] [<ffffffff8107afae>] kthread+0x8e/0xa0
> [ 811.702999] [<ffffffff81029b14>] kernel_thread_helper+0x4/0x10
> [ 811.702999] [<ffffffff813885bc>] ? restore_args+0x0/0x30
> [ 811.702999] [<ffffffff8107af20>] ? kthread+0x0/0xa0
> [ 811.702999] [<ffffffff81029b10>] ? kernel_thread_helper+0x0/0x10
>
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
> net/bluetooth/rfcomm/sock.c | 6 ++++--
> 1 files changed, 4 insertions(+), 2 deletions(-)
>
> diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
> index 44a6232..30cd80b 100644
> --- a/net/bluetooth/rfcomm/sock.c
> +++ b/net/bluetooth/rfcomm/sock.c
> @@ -82,12 +82,14 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
> static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
> {
> struct sock *sk = d->owner, *parent;
> + unsigned long flags;
> +
> if (!sk)
> return;
>
> BT_DBG("dlc %p state %ld err %d", d, d->state, err);
>
> - bh_lock_sock(sk);
> + spin_lock_irqsave(&sk->sk_lock.slock, flags);
>
> if (err)
> sk->sk_err = err;
> @@ -107,7 +109,7 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
> sk->sk_state_change(sk);
> }
>
> - bh_unlock_sock(sk);
> + spin_unlock_irqrestore(&sk->sk_lock.slock, flags);
>
> if (parent && sock_flag(sk, SOCK_ZAPPED)) {
> /* We have to drop DLC lock here, otherwise
I am missing an explanation why you fixed it this way. And also why thi
sis the right way to fix it. Directly referencing sk->sk_lock seems
pretty much wrong to me.
Regards
Marcel
^ permalink raw reply
* [PATCH] Bluetooth: Fix inconsistent lock state with RFCOMM
From: Gustavo F. Padovan @ 2010-08-14 14:46 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, Gustavo F. Padovan
From: Gustavo F. Padovan <padovan@profusion.mobi>
When receiving a rfcomm connection with the old dund deamon the following
inconsistent lock state happens:
[ 811.702999] =================================
[ 811.702999] [ INFO: inconsistent lock state ]
[ 811.702999] 2.6.35-rc1-01743-g41069ad-dirty #1
[ 811.702999] ---------------------------------
[ 811.702999] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
[ 811.702999] krfcommd/3892 [HC0[0]:SC0[0]:HE1:SE1] takes:
[ 811.702999] (slock-AF_BLUETOOTH){+.?...}, at: [<ffffffffa0189b56>] rfcomm_sk_state_change+0x46/0x170 [rfcomm]
[ 811.702999] {IN-SOFTIRQ-W} state was registered at:
[ 811.702999] [<ffffffff8108dfa6>] __lock_acquire+0x5b6/0x1560
[ 811.702999] [<ffffffff8108efaa>] lock_acquire+0x5a/0x70
[ 811.702999] [<ffffffff81387b2c>] _raw_spin_lock+0x2c/0x40
[ 811.702999] [<ffffffffa0043092>] 0xffffffffa0043092
[ 811.702999] [<ffffffffa0044a3f>] 0xffffffffa0044a3f
[ 811.702999] [<ffffffffa0047183>] 0xffffffffa0047183
[ 811.702999] [<ffffffffa004798b>] 0xffffffffa004798b
[ 811.702999] [<ffffffffa000db4b>] 0xffffffffa000db4b
[ 811.702999] [<ffffffff81067efb>] tasklet_action+0xcb/0xe0
[ 811.702999] [<ffffffff810685ee>] __do_softirq+0xae/0x150
[ 811.702999] [<ffffffff81029c0c>] call_softirq+0x1c/0x30
[ 811.702999] [<ffffffff8102bd75>] do_softirq+0x75/0xb0
[ 811.702999] [<ffffffff8106823d>] irq_exit+0x8d/0xa0
[ 811.702999] [<ffffffff8102b330>] do_IRQ+0x70/0xf0
[ 811.702999] [<ffffffff81388513>] ret_from_intr+0x0/0xf
[ 811.702999] [<ffffffff81027dfa>] cpu_idle+0x5a/0xb0
[ 811.702999] [<ffffffff81382934>] start_secondary+0x211/0x254
[ 811.702999] irq event stamp: 411
[ 811.702999] hardirqs last enabled at (411): [<ffffffff81068432>] local_bh_enable_ip+0x82/0xe0
[ 811.702999] hardirqs last disabled at (409): [<ffffffff8106860e>] __do_softirq+0xce/0x150
[ 811.702999] softirqs last enabled at (410): [<ffffffff8106863e>] __do_softirq+0xfe/0x150
[ 811.702999] softirqs last disabled at (391): [<ffffffff81029c0c>] call_softirq+0x1c/0x30
[ 811.702999]
[ 811.702999] other info that might help us debug this:
[ 811.702999] 2 locks held by krfcommd/3892:
[ 811.702999] #0: (rfcomm_mutex){+.+.+.}, at: [<ffffffffa0188744>] rfcomm_run+0x174/0xb20 [rfcomm]
[ 811.702999] #1: (&(&d->lock)->rlock){+.+...}, at: [<ffffffffa0186223>] rfcomm_dlc_accept+0x53/0x100 [rfcomm]
[ 811.702999]
[ 811.702999] stack backtrace:
[ 811.702999] Pid: 3892, comm: krfcommd Tainted: G W 2.6.35-rc1-01743-g41069ad-dirty #1
[ 811.702999] Call Trace:
[ 811.702999] [<ffffffff8108c541>] print_usage_bug+0x171/0x180
[ 811.702999] [<ffffffff8108d323>] mark_lock+0x333/0x400
[ 811.702999] [<ffffffff8108e02a>] __lock_acquire+0x63a/0x1560
[ 811.702999] [<ffffffff8108e515>] ? __lock_acquire+0xb25/0x1560
[ 811.702999] [<ffffffff8108efaa>] lock_acquire+0x5a/0x70
[ 811.702999] [<ffffffffa0189b56>] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm]
[ 811.702999] [<ffffffff81387b2c>] _raw_spin_lock+0x2c/0x40
[ 811.702999] [<ffffffffa0189b56>] ? rfcomm_sk_state_change+0x46/0x170 [rfcomm]
[ 811.702999] [<ffffffffa0189b56>] rfcomm_sk_state_change+0x46/0x170 [rfcomm]
[ 811.702999] [<ffffffffa0186239>] rfcomm_dlc_accept+0x69/0x100 [rfcomm]
[ 811.702999] [<ffffffffa0186a49>] rfcomm_check_accept+0x59/0xd0 [rfcomm]
[ 811.702999] [<ffffffffa0187cab>] rfcomm_recv_frame+0x9fb/0x1320 [rfcomm]
[ 811.702999] [<ffffffff8138827b>] ? _raw_spin_unlock_irqrestore+0x3b/0x60
[ 811.702999] [<ffffffff8108d72d>] ? trace_hardirqs_on_caller+0x13d/0x180
[ 811.702999] [<ffffffff8108d77d>] ? trace_hardirqs_on+0xd/0x10
[ 811.702999] [<ffffffffa01887f1>] rfcomm_run+0x221/0xb20 [rfcomm]
[ 811.702999] [<ffffffff81385667>] ? schedule+0x267/0x5d0
[ 811.702999] [<ffffffffa01885d0>] ? rfcomm_run+0x0/0xb20 [rfcomm]
[ 811.702999] [<ffffffff8107afae>] kthread+0x8e/0xa0
[ 811.702999] [<ffffffff81029b14>] kernel_thread_helper+0x4/0x10
[ 811.702999] [<ffffffff813885bc>] ? restore_args+0x0/0x30
[ 811.702999] [<ffffffff8107af20>] ? kthread+0x0/0xa0
[ 811.702999] [<ffffffff81029b10>] ? kernel_thread_helper+0x0/0x10
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
net/bluetooth/rfcomm/sock.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 44a6232..30cd80b 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -82,12 +82,14 @@ static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb)
static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
{
struct sock *sk = d->owner, *parent;
+ unsigned long flags;
+
if (!sk)
return;
BT_DBG("dlc %p state %ld err %d", d, d->state, err);
- bh_lock_sock(sk);
+ spin_lock_irqsave(&sk->sk_lock.slock, flags);
if (err)
sk->sk_err = err;
@@ -107,7 +109,7 @@ static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err)
sk->sk_state_change(sk);
}
- bh_unlock_sock(sk);
+ spin_unlock_irqrestore(&sk->sk_lock.slock, flags);
if (parent && sock_flag(sk, SOCK_ZAPPED)) {
/* We have to drop DLC lock here, otherwise
--
1.7.1.1
^ permalink raw reply related
* [PATCH] Bluetooth: Implement LE Set Advertise Enable cmd
From: Anderson Briglia @ 2010-08-13 21:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Briglia
This patch implements LE Set Advertise Enable command for dual mode and
Low Energy hci controllers.
Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
---
include/net/bluetooth/hci.h | 7 +++++++
net/bluetooth/hci_core.c | 15 +++++++++++++++
net/bluetooth/hci_event.c | 27 +++++++++++++++++++++++++++
net/bluetooth/hci_sock.c | 1 +
4 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index bcbdd6d..1713849 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -76,6 +76,7 @@ enum {
HCI_INQUIRY,
HCI_RAW,
+ HCI_LE_ADV,
};
/* HCI ioctl defines */
@@ -104,6 +105,7 @@ enum {
#define HCIUNBLOCKADDR _IOW('H', 231, int)
#define HCIINQUIRY _IOR('H', 240, int)
+#define HCILESETADV _IOR('H', 241, int)
/* HCI timeouts */
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
@@ -593,6 +595,11 @@ struct hci_rp_read_bd_addr {
bdaddr_t bdaddr;
} __packed;
+/* --- HCI LE Commands --- */
+#define HCI_OP_LE_SET_ADVERTISE_ENABLE 0x200a
+ #define ADVERTISE_ENABLED 0x01
+ #define ADVERTISE_DISABLED 0x00
+
/* ---- HCI Events ---- */
#define HCI_EV_INQUIRY_COMPLETE 0x01
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index c52f091..2bdb954 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -294,6 +294,16 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy);
}
+static void hci_le_advertise_req(struct hci_dev *hdev, unsigned long opt)
+{
+ __u8 leadv = opt;
+
+ BT_DBG("%s %x", hdev->name, leadv);
+
+ /* LE Advertising mode */
+ hci_send_cmd(hdev, HCI_OP_LE_SET_ADVERTISE_ENABLE, 1, &leadv);
+}
+
/* Get HCI device by index.
* Device is held on return. */
struct hci_dev *hci_dev_get(int index)
@@ -739,6 +749,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
hdev->sco_pkts = *((__u16 *) &dr.dev_opt + 0);
break;
+ case HCILESETADV:
+ err = hci_request(hdev, hci_le_advertise_req, dr.dev_opt,
+ msecs_to_jiffies(HCI_INIT_TIMEOUT));
+ break;
+
default:
err = -EINVAL;
break;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index bfef5ba..c86c655 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -822,6 +822,29 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev);
}
+static void hci_cc_le_set_advertise(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ __u8 status = *((__u8 *) skb->data);
+ void *sent;
+
+ BT_DBG("%s status 0x%x", hdev->name, status);
+
+ sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADVERTISE_ENABLE);
+ if (!sent)
+ return;
+
+ if (!status) {
+ __u8 param = *((__u8 *) sent);
+
+ clear_bit(HCI_LE_ADV, &hdev->flags);
+
+ if (param & ADVERTISE_ENABLED)
+ set_bit(HCI_LE_ADV, &hdev->flags);
+ }
+
+ hci_req_complete(hdev, status);
+}
+
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -1310,6 +1333,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_read_bd_addr(hdev, skb);
break;
+ case HCI_OP_LE_SET_ADVERTISE_ENABLE:
+ hci_cc_le_set_advertise(hdev, skb);
+ break;
+
default:
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
break;
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 83acd16..0286d32 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -335,6 +335,7 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
case HCISETLINKMODE:
case HCISETACLMTU:
case HCISETSCOMTU:
+ case HCILESETADV:
if (!capable(CAP_NET_ADMIN))
return -EACCES;
return hci_dev_cmd(cmd, argp);
--
1.7.0.4
^ permalink raw reply related
* Re: [RFC 3/7] Bluetooth: Add FCS awareness to L2CAP HCI fragmentation.
From: Gustavo F. Padovan @ 2010-08-13 15:41 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, marcel, rshaffer
In-Reply-To: <alpine.DEB.2.00.1008121626340.8460@linux-sea-02>
Hi Mat,
* Mat Martineau <mathewm@codeaurora.org> [2010-08-12 16:36:57 -0700]:
>
>
> On Wed, 11 Aug 2010, Gustavo F. Padovan wrote:
>
> >Hi Mat,
> >
> >* Gustavo F. Padovan <gustavo@padovan.org> [2010-08-11 00:35:41 -0300]:
> >
> >>* Mat Martineau <mathewm@codeaurora.org> [2010-08-10 12:15:00 -0700]:
> >>
> >>>In order to not limit ERTM and streaming mode PDUs to the HCI MTU
> >>>size, L2CAP must be able to split PDUs in to multple HCI fragments.
> >>>This is done by allocating space for the FCS in the last fragment.
> >>>
> >>>Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> >>>---
> >>> net/bluetooth/l2cap.c | 39 ++++++++++++++++++++++++++++++++++-----
> >>> 1 files changed, 34 insertions(+), 5 deletions(-)
> >>>
> >>>diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
> >>>index aa69c84..b485c4a 100644
> >>>--- a/net/bluetooth/l2cap.c
> >>>+++ b/net/bluetooth/l2cap.c
> >>>@@ -1664,31 +1664,63 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
> >>> {
> >>> struct l2cap_conn *conn = l2cap_pi(sk)->conn;
> >>> struct sk_buff **frag;
> >>>+ struct sk_buff *final;
> >>> int err, sent = 0;
> >>>
> >>>+ BT_DBG("sk %p, msg %p, len %d, count %d, skb %p", sk,
> >>>+ msg, (int)len, (int)count, skb);
> >>>+
> >>> if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
> >>> return -EFAULT;
> >>>
> >>> sent += count;
> >>> len -= count;
> >>>+ final = skb;
> >>>
> >>> /* Continuation fragments (no L2CAP header) */
> >>> frag = &skb_shinfo(skb)->frag_list;
> >>> while (len) {
> >>>+ int skblen;
> >>> count = min_t(unsigned int, conn->mtu, len);
> >>>
> >>>- *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
> >>>+ /* Add room for the FCS if it fits */
> >>>+ if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16 &&
> >>>+ len + L2CAP_FCS_SIZE <= conn->mtu)
> >>
> >>You don't need to check for (len + L2CAP_FCS_SIZE <= conn=mtu) here.
> >>Section 5.1 point that:
> >>
> >>"Unlike the B-Frame length field, the I-frame length field may be greater
> >>than the configured MTU because it includes the octet lengths of the
> >>Control, L2CAP SDU Length (when present), and frame check sequence
> >>fields as well as the Information octets."
> >>
> >>From that I understand "len <=" and not "len + L2CAP_FCS_SIZE <="
> >
> >So here you might want to the check if we support FCS, and then add 2 to
> >skblen.
>
> That's what the code does, without violating the HCI MTU.
Yes, you are right!
>
> >>>+ skblen = count + L2CAP_FCS_SIZE;
> >>>+ else
> >>>+ skblen = count;
> >>>+
> >>>+ *frag = bt_skb_send_alloc(sk, skblen,
> >>>+ msg->msg_flags & MSG_DONTWAIT, &err);
> >>> if (!*frag)
> >>> return -EFAULT;
> >>>- if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
> >>>+
> >>>+ if (memcpy_fromiovec(skb_put(*frag, count),
> >>>+ msg->msg_iov, count))
> >>> return -EFAULT;
> >>>
> >>> sent += count;
> >>> len -= count;
> >>>
> >>>+ final = *frag;
> >>>+
> >>> frag = &(*frag)->next;
> >>> }
> >>>
> >>>+ if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
> >>>+ if (skb_tailroom(final) < L2CAP_FCS_SIZE) {
> >>>+ *frag = bt_skb_send_alloc(sk, L2CAP_FCS_SIZE,
> >>>+ msg->msg_flags & MSG_DONTWAIT,
> >>>+ &err);
> >
> >Why do we need to check for FCS again? We already added it required
> >space to the last fragment.
> >
>
> If there was room in the HCI fragment, count+2 bytes were allocated
> with bt_skb_send_alloc. However, only count bytes were used by
> skb_put.
>
> This final block of code is doing two things:
>
> 1. Allocating a final HCI fragment for the FCS if there was not
> room for the FCS in the last data fragment.
>
> 2. Doing the skb_put for the FCS bytes.
>
> I will add some comments to this code to help clarify what's going on.
Ok, and do the other way around in the if:
if (l2cap_pi(sk)->fcs != L2CAP_FCS_CRC16)
return sent;
if (skb_tailroom(...
--
Gustavo F. Padovan
http://padovan.org
^ permalink raw reply
* [PATCH v2] Firmware download for Qualcomm Bluetooth devices
From: Matthew Wilson @ 2010-08-13 15:33 UTC (permalink / raw)
To: linux-bluetooth; +Cc: marcel, johan.hedberg, rshaffer, Matthew Wilson
In-Reply-To: <4C620A8A.9030707@codeaurora.org>
Configures device address from hciattach parameter.
UART speed limited to 115200.
Requires separate device specific firmware.
---
Makefile.tools | 3 +-
tools/hciattach.c | 8 ++
tools/hciattach.h | 1 +
tools/hciattach_qualcomm.c | 279 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 290 insertions(+), 1 deletions(-)
create mode 100644 tools/hciattach_qualcomm.c
diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..0ce7b75 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,7 +23,8 @@ tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
tools/hciattach_ti.c \
- tools/hciattach_tialt.c
+ tools/hciattach_tialt.c \
+ tools/hciattach_qualcomm.c
tools_hciattach_LDADD = lib/libbluetooth.la
tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 81aea7b..4d4b0a1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -299,6 +299,11 @@ static int texasalt(int fd, struct uart_t *u, struct termios *ti)
return texasalt_init(fd, u->speed, ti);
}
+static int qualcomm(int fd, struct uart_t *u, struct termios *ti)
+{
+ return qualcomm_init(fd, u->speed, ti, u->bdaddr);
+}
+
static int read_check(int fd, void *buf, int count)
{
int res;
@@ -1073,6 +1078,9 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+ /* QUALCOMM BTS */
+ { "qualcomm", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, qualcomm },
+
{ NULL, 0 }
};
diff --git a/tools/hciattach.h b/tools/hciattach.h
index c0b80a1..3d5605b 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -49,3 +49,4 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
diff --git a/tools/hciattach_qualcomm.c b/tools/hciattach_qualcomm.c
new file mode 100644
index 0000000..31ca3c8
--- /dev/null
+++ b/tools/hciattach_qualcomm.c
@@ -0,0 +1,279 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/poll.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+#define FAILIF(x, args...) do { \
+ if (x) { \
+ fprintf(stderr, ##args); \
+ return -1; \
+ } \
+} while(0)
+
+typedef struct {
+ uint8_t uart_prefix;
+ hci_event_hdr hci_hdr;
+ evt_cmd_complete cmd_complete;
+ uint8_t status;
+ uint8_t data[16];
+} __attribute__((packed)) command_complete_t;
+
+
+static int read_command_complete(int fd, unsigned short opcode, unsigned char len) {
+ command_complete_t resp;
+ unsigned char vsevent[512];
+ int n;
+
+ /* Read reply. */
+ n = read_hci_event(fd, vsevent, sizeof(vsevent));
+ FAILIF(n < 0, "Failed to read response");
+
+ FAILIF(vsevent[1] != 0xFF, "Failed to read response");
+
+ n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
+ FAILIF(n < 0, "Failed to read response");
+
+ FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */
+ "Error in response: not a cmd-complete event, "
+ "but 0x%02x!\n", resp.hci_hdr.evt);
+
+ FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */
+ "Error in response: plen is not >= 4, but 0x%02x!\n",
+ resp.hci_hdr.plen);
+
+ /* cmd-complete event: opcode */
+ FAILIF(resp.cmd_complete.opcode != 0,
+ "Error in response: opcode is 0x%04x, not 0!",
+ resp.cmd_complete.opcode);
+
+ return resp.status == 0 ? 0 : -1;
+}
+
+static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s) {
+
+ int fw = open(firmware, O_RDONLY);
+
+ fprintf(stdout, "Opening firmware file: %s\n", firmware);
+
+ FAILIF(fw < 0,
+ "Could not open firmware file %s: %s (%d).\n",
+ firmware, strerror(errno), errno);
+
+ fprintf(stdout, "Uploading firmware...\n");
+ do {
+ /* Read each command and wait for a response. */
+ unsigned char data[1024];
+ unsigned char cmdp[1 + sizeof(hci_command_hdr)];
+ hci_command_hdr *cmd = (hci_command_hdr *)(cmdp + 1);
+ int nr;
+ nr = read(fw, cmdp, sizeof(cmdp));
+ if (!nr)
+ break;
+ FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n");
+ FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n");
+
+ FAILIF(read(fw, data, cmd->plen) != cmd->plen,
+ "Could not read %d bytes of data for command with opcode %04x!\n",
+ cmd->plen,
+ cmd->opcode);
+
+ if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) {
+ bdaddr_t bdaddr;
+ if (bdaddr_s != NULL) {
+ (void) str2ba(bdaddr_s, &bdaddr);
+ memcpy(&data[3], &bdaddr, sizeof(bdaddr_t));
+ }
+ }
+
+ {
+ int nw;
+ struct iovec iov_cmd[2];
+ iov_cmd[0].iov_base = cmdp;
+ iov_cmd[0].iov_len = sizeof(cmdp);
+ iov_cmd[1].iov_base = data;
+ iov_cmd[1].iov_len = cmd->plen;
+ nw = writev(fd, iov_cmd, 2);
+ FAILIF(nw != (int) sizeof(cmdp) + cmd->plen,
+ "Could not send entire command (sent only %d bytes)!\n",
+ nw);
+ }
+
+ /* Wait for response */
+ if (read_command_complete(fd,
+ cmd->opcode,
+ cmd->plen) < 0) {
+ return -1;
+ }
+
+ } while(1);
+ fprintf(stdout, "Firmware upload successful.\n");
+
+ close(fw);
+ return 0;
+}
+
+int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr)
+{
+ struct timespec tm = {0, 50000};
+ char cmd[5];
+ unsigned char resp[100]; /* Response */
+ char fw[100];
+ int n;
+
+ memset(resp,'\0', 100);
+
+ /* Get Manufacturer and LMP version */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x01;
+ cmd[2] = 0x10;
+ cmd[3] = 0x00;
+
+ do {
+ n = write(fd, cmd, 4);
+ if (n < 0) {
+ perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");
+ return -1;
+ }
+ if (n < 4) {
+ fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
+ return -1;
+ }
+
+ /* Read reply. */
+ if (read_hci_event(fd, resp, 100) < 0) {
+ perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");
+ return -1;
+ }
+
+ /* Wait for command complete event for our Opcode */
+ } while (resp[4] != cmd[1] && resp[5] != cmd[2]);
+
+ /* Verify manufacturer */
+ if ((resp[11] & 0xFF) != 0x1d)
+ fprintf(stderr,"WARNING : module's manufacturer is not Qualcomm\n");
+
+ /* Print LMP version */
+ fprintf(stderr, "Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF);
+
+ /* Print LMP subversion */
+ {
+ unsigned short lmp_subv = resp[13] | (resp[14] << 8);
+
+ fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n", lmp_subv);
+
+ }
+
+ /* Get SoC type */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x00;
+ cmd[2] = 0xFC;
+ cmd[3] = 0x01;
+ cmd[4] = 0x06;
+
+ do {
+ n = write(fd, cmd, 5);
+ if (n < 0) {
+ perror("Failed to write init command");
+ return -1;
+ }
+ if (n < 5) {
+ fprintf(stderr, "Wanted to write 5 bytes, could only write %d. Stop\n", n);
+ return -1;
+ }
+
+ /* Read reply. */
+ if ((n = read_hci_event(fd, resp, 100)) < 0) {
+ perror("Failed to read init response");
+ return -1;
+ }
+
+ } while (resp[3] != 0 && resp[4] != 2);
+
+ snprintf(fw, sizeof(fw),
+ "/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin",
+ resp[18], resp[19], resp[20], resp[21],
+ resp[22], resp[23],
+ resp[32], resp[33], resp[34], resp[35]);
+
+ /* Wait for command complete event for our Opcode */
+ if (read_hci_event(fd, resp, 100) < 0) {
+ perror("Failed to read init response");
+ return -1;
+ }
+
+ qualcomm_load_firmware(fd, fw, bdaddr);
+
+ /* Reset */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0C;
+ cmd[3] = 0x00;
+
+ do {
+ n = write(fd, cmd, 4);
+ if (n < 0) {
+ perror("Failed to write reset command");
+ return -1;
+ }
+ if (n < 4) {
+ fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
+ return -1;
+ }
+
+ /* Read reply. */
+ if ((n = read_hci_event(fd, resp, 100)) < 0) {
+ perror("Failed to read reset response");
+ return -1;
+ }
+
+ } while (resp[4] != cmd[1] && resp[5] != cmd[2]);
+
+ nanosleep(&tm, NULL);
+ return 0;
+}
--
1.7.1.1
--
Matthew Wilson
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply related
* Re: resending patch to retry reset in case it failed
From: Ville Tervo @ 2010-08-13 14:08 UTC (permalink / raw)
To: Oliver Neukum; +Cc: Marcel Holtmann, linux-bluetooth, linux-usb
In-Reply-To: <201008131556.22623.oneukum@suse.de>
Hi Oliver,
On Fri, Aug 13, 2010 at 9:56 AM, Oliver Neukum <oneukum@suse.de> wrote:
>>
>> Could you share also "hciconfig hci0 revision" and "hciconfig hci0
>> version" info. And laptop model you have the chip build in.
>
> The device reported:
>
> localhost:/tmp # hciconfig hci0 version
> hci0: =A0 Type: USB
> =A0 =A0 =A0 =A0BD Address: 00:27:13:98:49:7E ACL MTU: 1021:8 SCO MTU: 64:=
1
> =A0 =A0 =A0 =A0HCI Ver: 3.0 (0x5) HCI Rev: 0x1e1 LMP Ver: 3.0 (0x5) LMP S=
ubver: 0x4203
> =A0 =A0 =A0 =A0Manufacturer: Broadcom Corporation (15)
> localhost:/tmp # hciconfig hci0 revision
> hci0: =A0 Type: USB
> =A0 =A0 =A0 =A0BD Address: 00:27:13:98:49:7E ACL MTU: 1021:8 SCO MTU: 64:=
1
> =A0 =A0 =A0 =A0Firmware 225.66 / 3
>
> The laptop is a prototype. All laptops it was installed in showed the sam=
e
> problem.
Thanks. I don't have access to that hardware and cannot do much without.
hcidump from chip initialization might reveal something. Could you
send the dump also?
--=20
Ville
^ permalink raw reply
* Re: resending patch to retry reset in case it failed
From: Oliver Neukum @ 2010-08-13 13:56 UTC (permalink / raw)
To: Ville Tervo; +Cc: Marcel Holtmann, linux-bluetooth, linux-usb
In-Reply-To: <AANLkTi=odMckPT4pAOiQJm+1NWbk0diL=-9=yKBfj66W@mail.gmail.com>
Am Freitag, 13. August 2010, 15:20:08 schrieb Ville Tervo:
> On Thu, Aug 12, 2010 at 8:16 AM, Oliver Neukum <oneukum@suse.de> wrote:
> > Am Donnerstag, 12. August 2010, 13:25:23 schrieb Marcel Holtmann:
> >> Hi Oliver,
> >>
> >> > may I ask what happened to this patch?
> >> > Do you take it, want modifications or reject it?
> >> >
> >> > Regards
> >> > Oliver
> >> >
> >> > From af61f0663f095599003290b13ad6fadee1d4fb25 Mon Sep 17 00:00:00 2001
> >> > From: Oliver Neukum <oliver@neukum.org>
> >> > Date: Tue, 6 Jul 2010 08:08:42 +0200
> >> > Subject: [PATCH] bluetooth: retry reset for devices that fail
> >> >
> >> > Some devices fail to reset properly at the first attempt to reset
> >> > them under unknown circumstances. Failures can be identified by
> >> > an invalid btaddr. Retry in those cases.
> >>
> >> I was pondering about it and haven't really made up my mind with this
> >> stuff. To be honest, I don't like the patch a little bit. I can see your
> >> point why you want it, but the patch is a bit too ugly for my taste.
> >
> > I am very open to alternatives. But without that it is needed to make the
> > hardware work.
> >
> >> Tell me which device is causing this and I might be able to reproduce
> >> this and find small less ugly fix.
> >
> >
> > I happens with this hardware from Broadcom. There may be others I don't
> > know about. It is an internal dongle. I don't know whether it can be found in
> > external hardware.
> >
>
> Could you share also "hciconfig hci0 revision" and "hciconfig hci0
> version" info. And laptop model you have the chip build in.
The device reported:
localhost:/tmp # hciconfig hci0 version
hci0: Type: USB
BD Address: 00:27:13:98:49:7E ACL MTU: 1021:8 SCO MTU: 64:1
HCI Ver: 3.0 (0x5) HCI Rev: 0x1e1 LMP Ver: 3.0 (0x5) LMP Subver: 0x4203
Manufacturer: Broadcom Corporation (15)
localhost:/tmp # hciconfig hci0 revision
hci0: Type: USB
BD Address: 00:27:13:98:49:7E ACL MTU: 1021:8 SCO MTU: 64:1
Firmware 225.66 / 3
The laptop is a prototype. All laptops it was installed in showed the same
problem.
Regards
Oliver
^ permalink raw reply
* Re: [PATCH 1/3] Add mode callback to btd_adapter
From: Daniel Örstadius @ 2010-08-13 13:43 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20100813124102.GA3546@jh-x301>
[-- Attachment #1: Type: text/plain, Size: 846 bytes --]
On Fri, Aug 13, 2010 at 3:41 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> On Fri, Aug 13, 2010, Daniel Örstadius wrote:
>> +typedef void (*btd_adapter_mode_cb) (struct btd_adapter *adapter,
>> + gboolean powered);
>> +void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
>> + btd_adapter_mode_cb cb);
>
> In general this seems fine, but I think for completeness there should
> also be a unregister function. Also, since we've traditionally used the
> term mode to include also the discoverable state the name should
> probably be something like btd_adapter_register_powered_callback and
> btd_adapter_powered_cb.
>
Thanks for the feedback. Replaced 'mode' with 'powered' and added the
unregister function.
/Daniel
[-- Attachment #2: 0001-Add-powered-callback-to-btd_adapter.patch --]
[-- Type: text/x-patch, Size: 3090 bytes --]
From ead124babce407c4ec25cdce073b456979e5d431 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 16:38:08 +0300
Subject: [PATCH] Add powered callback to btd_adapter
With this patch callback functions can be registered to the
btd_adapter struct. The functions are then called when the powered
state of the adapter changes, with a boolean argument indicating
the new state. The reason for adding the functionality is that the
Maemo6 MCE plugin needs to be notified when the adapter is powered
on or off.
---
src/adapter.c | 32 ++++++++++++++++++++++++++++++++
src/adapter.h | 7 +++++++
2 files changed, 39 insertions(+), 0 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index fc1e123..4ad4165 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -135,6 +135,8 @@ struct btd_adapter {
gboolean cache_enable;
gint ref;
+
+ GSList *powered_callbacks;
};
static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
@@ -2203,6 +2205,18 @@ static void adapter_disable_cod_cache(struct btd_adapter *adapter)
adapter->pending_cod = adapter->wanted_cod;
}
+static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
+ gboolean powered)
+{
+ GSList *l;
+
+ for (l = adapter->powered_callbacks; l; l = l->next) {
+ btd_adapter_powered_cb cb = l->data;
+
+ cb(adapter, powered);
+ }
+}
+
static int adapter_up(struct btd_adapter *adapter, const char *mode)
{
char srcaddr[18];
@@ -2283,6 +2297,8 @@ proceed:
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
+ call_adapter_powered_callbacks(adapter, TRUE);
+
adapter_disable_cod_cache(adapter);
return 0;
@@ -2487,6 +2503,8 @@ int adapter_stop(struct btd_adapter *adapter)
adapter->cache_enable = TRUE;
adapter->pending_cod = 0;
+ call_adapter_powered_callbacks(adapter, FALSE);
+
info("Adapter %s has been disabled", adapter->path);
return 0;
@@ -3422,3 +3440,17 @@ int adapter_ops_setup(void)
return adapter_ops->setup();
}
+
+void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
+ btd_adapter_powered_cb cb)
+{
+ adapter->powered_callbacks =
+ g_slist_append(adapter->powered_callbacks, cb);
+}
+
+void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
+ btd_adapter_powered_cb cb)
+{
+ adapter->powered_callbacks =
+ g_slist_remove(adapter->powered_callbacks, cb);
+}
diff --git a/src/adapter.h b/src/adapter.h
index a7eca0e..58853ac 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -188,3 +188,10 @@ struct btd_adapter_ops {
int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops);
int adapter_ops_setup(void);
+
+typedef void (*btd_adapter_powered_cb) (struct btd_adapter *adapter,
+ gboolean powered);
+void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
+ btd_adapter_powered_cb cb);
+void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
+ btd_adapter_powered_cb cb);
--
1.6.0.4
^ permalink raw reply related
* Re: resending patch to retry reset in case it failed
From: Ville Tervo @ 2010-08-13 13:20 UTC (permalink / raw)
To: Oliver Neukum; +Cc: Marcel Holtmann, linux-bluetooth, linux-usb
In-Reply-To: <201008121416.31808.oneukum@suse.de>
On Thu, Aug 12, 2010 at 8:16 AM, Oliver Neukum <oneukum@suse.de> wrote:
> Am Donnerstag, 12. August 2010, 13:25:23 schrieb Marcel Holtmann:
>> Hi Oliver,
>>
>> > may I ask what happened to this patch?
>> > Do you take it, want modifications or reject it?
>> >
>> > =A0 =A0 Regards
>> > =A0 =A0 =A0 =A0 =A0 =A0 Oliver
>> >
>> > From af61f0663f095599003290b13ad6fadee1d4fb25 Mon Sep 17 00:00:00 2001
>> > From: Oliver Neukum <oliver@neukum.org>
>> > Date: Tue, 6 Jul 2010 08:08:42 +0200
>> > Subject: [PATCH] bluetooth: retry reset for devices that fail
>> >
>> > Some devices fail to reset properly at the first attempt to reset
>> > them under unknown circumstances. Failures can be identified by
>> > an invalid btaddr. Retry in those cases.
>>
>> I was pondering about it and haven't really made up my mind with this
>> stuff. To be honest, I don't like the patch a little bit. I can see your
>> point why you want it, but the patch is a bit too ugly for my taste.
>
> I am very open to alternatives. But without that it is needed to make the
> hardware work.
>
>> Tell me which device is causing this and I might be able to reproduce
>> this and find small less ugly fix.
>
>
> I happens with this hardware from Broadcom. There may be others I don't
> know about. It is an internal dongle. I don't know whether it can be foun=
d in
> external hardware.
>
Could you share also "hciconfig hci0 revision" and "hciconfig hci0
version" info. And laptop model you have the chip build in.
--=20
Ville
^ permalink raw reply
* Re: [PATCH 1/3] Add mode callback to btd_adapter
From: Johan Hedberg @ 2010-08-13 12:41 UTC (permalink / raw)
To: Daniel Örstadius; +Cc: linux-bluetooth
In-Reply-To: <AANLkTi=Jh5fsqye6-Ry+VSNWftufDFCdyNEn6fcNrW84@mail.gmail.com>
Hi Daniel,
On Fri, Aug 13, 2010, Daniel Örstadius wrote:
> +typedef void (*btd_adapter_mode_cb) (struct btd_adapter *adapter,
> + gboolean powered);
> +void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
> + btd_adapter_mode_cb cb);
In general this seems fine, but I think for completeness there should
also be a unregister function. Also, since we've traditionally used the
term mode to include also the discoverable state the name should
probably be something like btd_adapter_register_powered_callback and
btd_adapter_powered_cb.
Johan
^ permalink raw reply
* Re: bluetooth profile source code
From: Marcel Holtmann @ 2010-08-13 12:20 UTC (permalink / raw)
To: Viral Mehta; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <70376CA23424B34D86F1C7DE6B99734306D4C3CC13@VSHINMSMBX01.vshodc.lntinfotech.com>
Hi Viral,
> I am looking for some BT profile source code.
> I was able to find out for OBEX source code,
>
> But, I could not find any source cod for
> Headset Profile
> A2DP profile
> HandsFree Profile
>
> Surprisingly, is there no open source code for all these profiles ?
> Or I am just not able to google properly !!??
seems your Google Mojo is not high enough:
http://git.kernel.org/?p=bluetooth/bluez.git;a=summary
http://git.kernel.org/?p=bluetooth/obexd.git;a=summary
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Add support for FAX number in phonebook-tracker.c
From: Johan Hedberg @ 2010-08-13 12:19 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1281697117-23072-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Fri, Aug 13, 2010, Radoslaw Jablonski wrote:
> Previously all fax numbers were treated as home phone numbers. Now
> fetching fax field as additional column in tracker query. Data from this
> column is filled as phone number with FAX type set. All pull queries are
> modified that way to suport fax number type.
> ---
> plugins/phonebook-tracker.c | 129 +++++++++++++++++++++++++++++++++---------
> 1 files changed, 101 insertions(+), 28 deletions(-)
Thanks. This patch is now also upstream.
Johan
^ permalink raw reply
* Re: [PATCH] Fix unnecessary checking for empty phones list
From: Johan Hedberg @ 2010-08-13 12:15 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1281681311-17074-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Fri, Aug 13, 2010, Radoslaw Jablonski wrote:
> Removed not needed anymore checking for empty list of phone numbers.
> ---
> plugins/vcard.c | 5 -----
> 1 files changed, 0 insertions(+), 5 deletions(-)
This patch is now upstream. Thanks.
Johan
^ permalink raw reply
* [PATCH] Add support for FAX number in phonebook-tracker.c
From: Radoslaw Jablonski @ 2010-08-13 10:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Previously all fax numbers were treated as home phone numbers. Now
fetching fax field as additional column in tracker query. Data from this
column is filled as phone number with FAX type set. All pull queries are
modified that way to suport fax number type.
---
plugins/phonebook-tracker.c | 129 +++++++++++++++++++++++++++++++++---------
1 files changed, 101 insertions(+), 28 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 8300fc7..705460d 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,20 +43,36 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 19
+#define CONTACTS_ID_COL 20
+#define PULL_QUERY_COL_AMOUNT 21
+#define COL_HOME_NUMBER 0
+#define COL_WORK_NUMBER 8
+#define COL_FAX_NUMBER 16
+#define COL_DATE 17
+#define COL_SENT 18
+#define COL_ANSWERED 19
#define CONTACTS_QUERY_ALL \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" " \
+ "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
"\"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . \
+ OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "}" \
+ "}" \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -80,13 +96,13 @@
"} GROUP BY ?c"
#define MISSED_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -94,7 +110,16 @@
"nmo:isSent false ; " \
"nmo:isAnswered false ." \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -118,13 +143,13 @@
"} ORDER BY DESC(nmo:receivedDate(?call))"
#define INCOMING_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -132,7 +157,16 @@
"nmo:isSent false ; " \
"nmo:isAnswered true ." \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -156,20 +190,29 @@
"} ORDER BY DESC(nmo:receivedDate(?call))"
#define OUTGOING_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -188,17 +231,17 @@
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
"} ORDER BY DESC(nmo:sentDate(?call))"
#define COMBINED_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"{ " \
@@ -206,7 +249,16 @@
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -218,7 +270,16 @@
"nmo:from ?c ; " \
"nmo:isSent false . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -248,17 +309,26 @@
#define CONTACTS_QUERY_FROM_URI \
- "SELECT nco:phoneNumber(?h) nco:fullname(<%s>) " \
+ "SELECT ?v nco:fullname(<%s>) " \
"nco:nameFamily(<%s>) nco:nameGiven(<%s>) " \
"nco:nameAdditional(<%s>) nco:nameHonorificPrefix(<%s>) " \
"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" " \
- "\"false\" <%s> " \
+ "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
+ "\"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
- "OPTIONAL { <%s> nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { <%s> nco:hasPhoneNumber ?h . \
+ OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "}" \
+ "}" \
"OPTIONAL { <%s> nco:hasEmailAddress ?e . } " \
"OPTIONAL { <%s> nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -660,7 +730,8 @@ static void pull_contacts(char **reply, int num_fields, void *user_data)
}
if (i == num_fields - 4 &&
- !g_str_equal(reply[19], TRACKER_DEFAULT_CONTACT_ME))
+ !g_str_equal(reply[CONTACTS_ID_COL],
+ TRACKER_DEFAULT_CONTACT_ME))
return;
data->index++;
@@ -691,12 +762,14 @@ add_entry:
contact->postal = g_strdup(reply[14]);
contact->country = g_strdup(reply[15]);
- set_call_type(contact, reply[16], reply[17], reply[18]);
+ set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
+ reply[COL_ANSWERED]);
add_numbers:
/* Adding phone numbers to contact struct */
- add_phone_number(contact, reply[0], TEL_TYPE_HOME);
- add_phone_number(contact, reply[8], TEL_TYPE_WORK);
+ add_phone_number(contact, reply[COL_HOME_NUMBER], TEL_TYPE_HOME);
+ add_phone_number(contact, reply[COL_WORK_NUMBER], TEL_TYPE_WORK);
+ add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
DBG("contact %p", contact);
@@ -868,7 +941,7 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
data->user_data = user_data;
data->cb = cb;
- return query_tracker(query, 20, pull_contacts, data);
+ return query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
}
int phonebook_get_entry(const char *folder, const char *id,
@@ -890,7 +963,7 @@ int phonebook_get_entry(const char *folder, const char *id,
query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
id, id, id, id, id, id, id);
- ret = query_tracker(query, 20, pull_contacts, data);
+ ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
g_free(query);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/3] Maemo6 MCE: handle race condition at startup
From: Daniel Örstadius @ 2010-08-13 9:19 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 415 bytes --]
Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the mode change callback. The off_requested member of btd_adapter
is used for the check, so it is set to FALSE when the adapter is
down.
/Daniel
[-- Attachment #2: 0001-Maemo6-MCE-handle-race-condition-at-startup.patch --]
[-- Type: text/x-patch, Size: 2622 bytes --]
From 16455aa43369853f2724d16751a41724df9a4fd5 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 11:41:37 +0300
Subject: [PATCH] Maemo6 MCE: handle race condition at startup
Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the mode change callback. The off_requested member of btd_adapter
is used for the check, so it is set to FALSE when the adapter is
down.
---
plugins/maemo6.c | 24 ++++++++++++++++++++++++
src/adapter.c | 1 +
2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 20e5c00..4a04fa9 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -50,6 +50,7 @@
static guint watch_id;
static DBusConnection *conn = NULL;
static gboolean mce_bt_set = FALSE;
+static gboolean collision = FALSE;
static gboolean mce_signal_callback(DBusConnection *connection,
DBusMessage *message, void *user_data)
@@ -112,6 +113,14 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
+ /* check if the adapter has not completed the initial power
+ cycle, if so delay action to mce_notify_powered */
+
+ collision = adapter_powering_down(adapter);
+
+ if (collision)
+ goto done;
+
if (mce_bt_set)
btd_adapter_switch_online(adapter);
else
@@ -133,6 +142,21 @@ static void adapter_mode_change(struct btd_adapter *adapter, gboolean powered)
if (mce_bt_set == powered)
return;
+ /* check if the plugin got the reply from the mce when the
+ adapter was not yet down during the power cycling when
+ bluetoothd is started */
+ if (collision) {
+ error("maemo6: collision");
+ collision = FALSE;
+
+ if (mce_bt_set)
+ btd_adapter_switch_online(adapter);
+ else
+ btd_adapter_switch_offline(adapter);
+
+ return;
+ }
+
/* set the mce value according to the state of the adapter */
msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ);
diff --git a/src/adapter.c b/src/adapter.c
index ff78539..712ca08 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2502,6 +2502,7 @@ int adapter_stop(struct btd_adapter *adapter)
adapter->state = DISCOVER_TYPE_NONE;
adapter->cache_enable = TRUE;
adapter->pending_cod = 0;
+ adapter->off_requested = FALSE;
adapter_mode_callbacks(adapter, FALSE);
--
1.6.0.4
^ permalink raw reply related
* [PATCH 2/3] Maemo6 MCE: listen to adapter mode changes
From: Daniel Örstadius @ 2010-08-13 9:19 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 437 bytes --]
Registers a callback in btd_adapter to get notified when
the powered state of the adapter is changed. This is needed
to update the state stored in the MCE if the adapter is powered
on or off using for example SetProperty(Powered). The current
setting of the MCE is saved in a variable and if the notification
to the plugin does not match this value the MCE is updated
accordingly using its DBus method for setting radio states.
/Daniel
[-- Attachment #2: 0001-Maemo6-MCE-listen-to-adapter-mode-changes.patch --]
[-- Type: text/x-patch, Size: 3567 bytes --]
From cc89e05c1d406e7d9021030e25e3b32a14bbd28c Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 11:18:32 +0300
Subject: [PATCH] Maemo6 MCE: listen to adapter mode changes
Registers a callback in btd_adapter to get notified when
the powered state of the adapter is changed. This is needed
to update the state stored in the MCE if the adapter is powered
on or off using for example SetProperty(Powered). The current
setting of the MCE is saved in a variable and if the notification
to the plugin does not match this value the MCE is updated
accordingly using its DBus method for setting radio states.
---
plugins/maemo6.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 2ed5f12..20e5c00 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -43,11 +43,13 @@
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
#define MCE_SIGNAL_PATH "/com/nokia/mce/signal"
+#define MCE_RADIO_STATES_CHANGE_REQ "req_radio_states_change"
#define MCE_RADIO_STATES_GET "get_radio_states"
#define MCE_RADIO_STATES_SIG "radio_states_ind"
static guint watch_id;
static DBusConnection *conn = NULL;
+static gboolean mce_bt_set = FALSE;
static gboolean mce_signal_callback(DBusConnection *connection,
DBusMessage *message, void *user_data)
@@ -66,7 +68,11 @@ static gboolean mce_signal_callback(DBusConnection *connection,
dbus_message_iter_get_basic(&args, &sigvalue);
DBG("got signal with value %u", sigvalue);
- if (sigvalue & MCE_RADIO_STATE_BLUETOOTH)
+ /* set the adapter according to the mce signal
+ and remember the value */
+ mce_bt_set = sigvalue & MCE_RADIO_STATE_BLUETOOTH;
+
+ if (mce_bt_set)
btd_adapter_switch_online(adapter);
else
btd_adapter_switch_offline(adapter);
@@ -102,13 +108,48 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
goto done;
}
- if (radio_states & MCE_RADIO_STATE_BLUETOOTH)
+ DBG("radio_states: %d", radio_states);
+
+ mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
+
+ if (mce_bt_set)
btd_adapter_switch_online(adapter);
+ else
+ btd_adapter_switch_offline(adapter);
done:
dbus_message_unref(reply);
}
+static void adapter_mode_change(struct btd_adapter *adapter, gboolean powered)
+{
+ DBusMessage *msg;
+ dbus_uint32_t radio_states = 0;
+ dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
+
+ DBG("adapter_mode_change called with %d", (int) powered);
+
+ /* nothing to do if the states match */
+ if (mce_bt_set == powered)
+ return;
+
+ /* set the mce value according to the state of the adapter */
+ msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
+ MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ);
+
+ if (powered)
+ radio_states = MCE_RADIO_STATE_BLUETOOTH;
+
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
+ DBUS_TYPE_UINT32, &radio_mask);
+
+ if (!dbus_connection_send(conn, msg, NULL))
+ error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
+
+ dbus_message_unref(msg);
+}
+
+
static int mce_probe(struct btd_adapter *adapter)
{
DBusMessage *msg;
@@ -132,6 +173,9 @@ static int mce_probe(struct btd_adapter *adapter)
watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
mce_signal_callback, adapter, NULL);
+
+ btd_adapter_register_mode_callback(adapter, adapter_mode_change);
+
return 0;
}
--
1.6.0.4
^ permalink raw reply related
* [PATCH 1/3] Add mode callback to btd_adapter
From: Daniel Örstadius @ 2010-08-13 9:18 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 346 bytes --]
With this patch callback functions can be registered to the
btd_adapter struct. The functions are then called when the powered
state of the adapter changes, with a boolean argument indicating
the new state. The reason for adding the functionality is that the
Maemo6 MCE plugin needs to be notified when the adapter is powered
on or off.
/Daniel
[-- Attachment #2: 0001-Add-mode-callback-to-btd_adapter.patch --]
[-- Type: text/x-patch, Size: 2710 bytes --]
From 489843b65a43773d678bdfe5a3669e3408fdaccc Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 10:30:37 +0300
Subject: [PATCH] Add mode callback to btd_adapter
With this patch callback functions can be registered to the
btd_adapter struct. The functions are then called when the powered
state of the adapter changes, with a boolean argument indicating
the new state. The reason for adding the functionality is that the
Maemo6 MCE plugin needs to be notified when the adapter is powered
on or off.
---
src/adapter.c | 25 +++++++++++++++++++++++++
src/adapter.h | 4 ++++
2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index fc1e123..ff78539 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -135,6 +135,8 @@ struct btd_adapter {
gboolean cache_enable;
gint ref;
+
+ GSList *mode_callbacks;
};
static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
@@ -2203,6 +2205,18 @@ static void adapter_disable_cod_cache(struct btd_adapter *adapter)
adapter->pending_cod = adapter->wanted_cod;
}
+static void adapter_mode_callbacks(struct btd_adapter *adapter,
+ gboolean powered)
+{
+ GSList *l;
+
+ for (l = adapter->mode_callbacks; l; l = l->next) {
+ btd_adapter_mode_cb cb = l->data;
+
+ cb(adapter, powered);
+ }
+}
+
static int adapter_up(struct btd_adapter *adapter, const char *mode)
{
char srcaddr[18];
@@ -2283,6 +2297,8 @@ proceed:
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
+ adapter_mode_callbacks(adapter, TRUE);
+
adapter_disable_cod_cache(adapter);
return 0;
@@ -2487,6 +2503,8 @@ int adapter_stop(struct btd_adapter *adapter)
adapter->cache_enable = TRUE;
adapter->pending_cod = 0;
+ adapter_mode_callbacks(adapter, FALSE);
+
info("Adapter %s has been disabled", adapter->path);
return 0;
@@ -3422,3 +3440,10 @@ int adapter_ops_setup(void)
return adapter_ops->setup();
}
+
+void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
+ btd_adapter_mode_cb cb)
+{
+ adapter->mode_callbacks =
+ g_slist_append(adapter->mode_callbacks, cb);
+}
diff --git a/src/adapter.h b/src/adapter.h
index a7eca0e..9c7cdf2 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -188,3 +188,7 @@ struct btd_adapter_ops {
int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops);
int adapter_ops_setup(void);
+typedef void (*btd_adapter_mode_cb) (struct btd_adapter *adapter,
+ gboolean powered);
+void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
+ btd_adapter_mode_cb cb);
--
1.6.0.4
^ permalink raw reply related
* Re: [PATCH 2nd version] IrMC sync server support
From: Marcel J.E. Mol @ 2010-08-13 9:05 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimSBnkvoN1x-Ak3Vgk8GNHFjTxoRJmQTV+3ZRys@mail.gmail.com>
On Fri, Aug 13, 2010 at 10:03:35AM +0300, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Fri, Aug 13, 2010 at 12:09 AM, Marcel Mol <marcel@mesa.nl> wrote:
> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> > Support for cal and note by just returning nothing.
> > ---
> > Makefile.am | 3 +
> > plugins/irmc.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > src/main.c | 10 +-
> > src/obex.h | 3 +-
> > 4 files changed, 521 insertions(+), 2 deletions(-)
> > create mode 100644 plugins/irmc.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 73e2f28..a2873f9 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -55,6 +55,9 @@ builtin_modules += pbap
> > builtin_sources += plugins/pbap.c plugins/phonebook.h \
> > plugins/vcard.h plugins/vcard.c
> >
> > +builtin_modules += irmc
> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> > +
>
> I guess we don't need phonebook.h, it is already listed in
> builtin-sources before.
Yes, I saw that too, but I think Makefile.am can be optimized even more.
I guess phonebook.h should not be mentioned at the pbabp line either,
but later on at the phonebook.c inclusion.
Also the vcard.h and vcard.h have 'nothing' to do with pbap. The exported
functions from those files are only used by phonebook-tracker...
I intended to file a Makfile.am patch later on....
But I made a few extra changes here so will create a new patch for IrMC
fixing the IrMC makefele.am part (and will nclude the name is NULL check
you mentioned below).
>
> > builtin_modules += syncevolution
> > builtin_sources += plugins/syncevolution.c
> >
> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> > new file mode 100644
> > index 0000000..fa7f91d
> > --- /dev/null
> > +++ b/plugins/irmc.c
> > @@ -0,0 +1,507 @@
> > +/*
> > + *
> > + * OBEX IrMC Sync Server
> > + *
> > + * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * 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
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <errno.h>
> > +#include <glib.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <arpa/inet.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +#include <openobex/obex.h>
> > +#include <openobex/obex_const.h>
> > +
> > +#include "plugin.h"
> > +#include "log.h"
> > +#include "obex.h"
> > +#include "service.h"
> > +#include "phonebook.h"
> > +#include "mimetype.h"
> > +#include "filesystem.h"
> > +#include "dbus.h"
> > +
> > +#define IRMC_CHANNEL 17
> > +
> > +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> > +<record> \
> > + <attribute id=\"0x0001\"> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0004\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0100\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0003\"/> \
> > + <uint8 value=\"%u\" name=\"channel\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0008\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0009\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + <uint16 value=\"0x0100\" name=\"version\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0100\"> \
> > + <text value=\"%s\" name=\"name\"/> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0301\"> \
> > + <sequence> \
> > + <uint8 value=\"0x01\"/> \
> > + </sequence> \
> > + </attribute> \
> > +</record>"
> > +
> > +
> > +struct aparam_header {
> > + uint8_t tag;
> > + uint8_t len;
> > + uint8_t val[0];
> > +} __attribute__ ((packed));
> > +
> > +#define DID_LEN 18
> > +
> > +struct irmc_session {
> > + struct obex_session *os;
> > + struct apparam_field *params;
> > + uint16_t entries;
> > + GString *buffer;
> > + char sn[DID_LEN];
> > + char did[DID_LEN];
> > + char manu[DID_LEN];
> > + char model[DID_LEN];
> > +};
> > +
> > +#define IRMC_TARGET_SIZE 9
> > +
> > +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> > + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> > +
> > +/*
> > + * FIXME:
> > + * the IrMC specs state the first vcard should be the owner
> > + * vcard. As there is no simple way to collect ownerdetails
> > + * just create an empty vcard (which is allowed according to the
> > + * specs).
> > + */
> > +static const char *owner_vcard =
> > + "BEGIN:VCARD\r\n"
> > + "VERSION:2.1\r\n"
> > + "N:\r\n"
> > + "TEL:\r\n"
> > + "X-IRMX-LUID:0\r\n"
> > + "END:VCARD\r\n";
> > +
> > +static void phonebook_size_result(const char *buffer, size_t bufsize,
> > + int vcards, int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("vcards %d", vcards);
> > +
> > + irmc->params->maxlistcount = vcards;
> > +}
> > +
> > +static void query_result(const char *buffer, size_t bufsize, int vcards,
> > + int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *s, *t;
> > +
> > + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> > +
> > + /* first add a 'owner' vcard */
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new(owner_vcard);
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
> > +
> > + /* loop around buffer and add X-IRMC-LUID attribs */
> > + s = buffer;
> > + while ((t = strstr(s, "UID:")) != NULL) {
> > + /* add upto UID: into buffer */
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + /*
> > + * add UID: line into buffer
> > + * Not sure if UID is still needed if X-IRMC-LUID is there
> > + */
> > + s = t;
> > + t = strstr(s, "\r\n");
> > + t += 2;
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + /* add X-IRMC-LUID with same number as UID */
> > + irmc->buffer = g_string_append_len(irmc->buffer,
> > + "X-IRMC-LUID:", 12);
> > + s += 4; /* point to uid number */
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + s = t;
> > + }
> > + /* add remaining bit of buffer */
> > + irmc->buffer = g_string_append(irmc->buffer, s);
> > +
> > + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> > +}
> > +
> > +static void *irmc_connect(struct obex_session *os, int *err)
> > +{
> > + struct irmc_session *irmc;
> > + struct apparam_field *param;
> > +
> > + DBG("");
> > +
> > + manager_register_session(os);
> > +
> > + irmc = g_new0(struct irmc_session, 1);
> > + irmc->os = os;
> > +
> > + /*
> > + * FIXME:
> > + * Ideally get capabilities info here and use that to define
> > + * IrMC DID and SN etc parameters.
> > + * For now lets used hostname and some 'random' value
> > + */
> > + gethostname(irmc->did, DID_LEN);
> > + strncpy(irmc->sn, "12345", DID_LEN);
> > + strncpy(irmc->manu, "obex", DID_LEN);
> > + strncpy(irmc->model, "mymodel", DID_LEN);
> > +
> > + /*
> > + * We need to know the number of contact/cal/nt entries
> > + * somewhere so why not do it now.
> > + */
> > + param = g_new0(struct apparam_field, 1);
> > + param->maxlistcount = 0; /* to count the number of vcards... */
> > + param->filter = 0x200085; /* UID TEL N VERSION */
> > + irmc->params = param;
> > + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> > + irmc);
> > +
> > + if (err)
> > + *err = 0;
> > +
> > + return irmc;
> > +}
> > +
> > +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> > + gboolean *stream, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *type = obex_get_type(os);
> > + const char *name = obex_get_name(os);
> > + char *path;
> > + int ret;
> > +
> > + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> > +
> > + path = g_strdup(name);
> > + *stream = TRUE;
> > +
> > + ret = obex_get_stream_start(os, path);
> > +
> > + g_free(path);
> > +
> > + return ret;
> > +}
> > +
> > +static void irmc_disconnect(struct obex_session *os, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("");
> > +
> > + manager_unregister_session(os);
> > +
> > + if (irmc->params) {
> > + if (irmc->params->searchval)
> > + g_free(irmc->params->searchval);
> > + g_free(irmc->params);
> > + }
> > + if (irmc->buffer) {
> > + string_free(irmc->buffer);
> > + irmc->buffer = NULL;
> > + }
> > +
> > + g_free(irmc);
> > +}
> > +
> > +static int irmc_chkput(struct obex_session *os, void *user_data)
> > +{
> > + DBG("");
> > + /* Reject all PUTs */
> > + return -EBADR;
> > +}
> > +
> > +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> > +{
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + g_string_append_printf(irmc->buffer,
> > + "MANU:%s\r\n"
> > + "MOD:%s\r\n"
> > + "SN:%s\r\n"
> > + "PB-TYPE-TX:VCARD2.1\r\n",
> > + irmc->manu, irmc->model, irmc->sn);
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open_pb(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + GString *mybuf;
> > + int ret;
> > +
> > + if (!g_strcmp0(name, ".vcf")) {
> > + /* how can we tell if the vcard count call already finished? */
> > + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> > + query_result, irmc);
> > + if (ret < 0) {
> > + DBG("phonebook_pull failed...");
> > + goto fail;
> > + }
> > + return irmc;
> > + }
> > +
> > + if (!g_strcmp0(name, "/info.log")) {
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "DID:%s\r\n",
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount, irmc->did);
> > + }
> > + else if (!strncmp(name, "/luid/", 6)) {
> > + name += 6;
> > + if (!g_strcmp0(name, "cc.log")) {
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> > + }
> > + else {
> > + int l = strlen(name);
> > + /* FIXME:
> > + * Reply the same to any *.log so we hopefully force a
> > + * full phonebook dump.
> > + * Is IEL:2 ok?
> > + */
> > + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> > + DBG("changelog request, force whole book");
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "SN:%s\r\n"
> > + "IEL:2\r\n"
> > + "DID:%s\r\n"
> > + "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "*\r\n",
> > + irmc->sn, irmc->did,
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount);
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > + }
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > +
> > + if (!irmc->buffer)
> > + irmc->buffer = mybuf;
> > + else {
> > + irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
> > + string_free(mybuf);
> > + }
> > +
> > + return irmc;
> > +
> > +fail:
> > + if (err)
> > + *err = ret;
> > +
> > + return NULL;
> > +}
> > +
> > +static void *irmc_open_cal(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + /* no suport yet. Just return an empty buffer. cal.vcs */
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open_nt(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + /* no suport yet. Just return an empty buffer. nt.vnt */
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open(const char *name, int oflag, mode_t mode,
> > + void *context, size_t *size, int *err)
> > +{
> > + struct irmc_session *irmc = context;
> > + int ret;
> > + const char *p;
> > +
> > + DBG("name %s context %p", name, context);
> > + if (oflag != O_RDONLY) {
> > + ret = -EPERM;
> > + goto fail;
> > + }
>
> Since Ive seen this many times we better put a check for NULL name
> here otherwise it may crash in the following line.
>
> > + if (strncmp(name, "telecom/", 8) != 0) {
> > + ret = -EBADR;
> > + goto fail;
> > + }
>
>
>
> --
> Luiz Augusto von Dentz
> Computer Engineer
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- marcel@mesa.nl 2630 AC Nootdorp
__==== www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- www.ruperthine.com
^ permalink raw reply
* Re: [PATCH] Bluetooth: Process HCI events in a workqueue instead of a tasklet
From: Marcel Holtmann @ 2010-08-13 8:35 UTC (permalink / raw)
To: David Vrabel; +Cc: linux-bluetooth
In-Reply-To: <4C647391.2090607@csr.com>
Hi David,
> >>> so I stuffed this now into bluetooth-testing tree and would like to see
> >>> some extra testing exposure. So far this has only been tested by myself.
> >>>
> >>> If there are no regression then this should make a lot of HCI and L2CAP
> >>> handling a lot simple.
> >> This may result in packets being processed in a different order to that
> >> which they were received in.
> >>
> >> e.g., what happens to an ACL packet processed before the connection
> >> complete event for that connection?
> >
> > good point. So we would either a) need to disable the RX tasklet when we
> > receive an event and schedule it for processing or b) process the ACL
> > data also in a workqueue.
>
> I've thought some more about this and I'm not sure disabling the tasklet
> is sufficient to prevent packets being reordered. Consider a transport
> that submits (in the same interrupt handler call) an ACL packet and an
> HCI event. The tasklet will be scheduled and then disabled until the
> event is processed in the workqueue.
>
> On the other hand, USB transports do not ensure any ordering between HCI
> event and ACL packets because they're received on different USB
> endpoints which could be processed in any order.
so lets see here. We expect that hci_recv_frame receives the events and
data packets in proper order. If it happens that the USB controller does
a different order, then it is the USB controllers problem. We just can't
fix that in the Bluetooth core since we don't know the expected order.
So we must assume whatever gets received via hci_recv_frame is the
correct order.
switch (bt_cb(skb)->pkt_type) {
case HCI_EVENT_PKT:
/* Queue frame for event processing */
skb_queue_tail(&hdev->evt_q, skb);
queue_work(hdev->workqueue, &hdev->evt_work);
break;
default:
/* Queue frame for rx task */
skb_queue_tail(&hdev->rx_q, skb);
tasklet_schedule(&hdev->rx_task);
break;
}
If we now disable the rx_task before scheduling the evt_work, then the
rx_task gets scheduled, but only run after we enable rx_task again. And
we enable the rx_task after hci_event_packet. So after we have created
any structure to handle the ACL and SCO data packets correctly.
I am not seeing your concern. At least not in the Bluetooth core. There
might be a few driver issues when the controller doesn't send us things
in order, but that is really a controller or driver issue at that point.
Coming to think about this, we might even go one step further here and
only enable the rx_task when we have an ACL link. That way if the
controller sends us an ACL packet before the Connection Complete event
we just queue it up. That would potentially solve issues that we have
seen with Broadcom controllers where the first ACL packet arrives too
early and BlueZ is just too fast.
We could even go one step further with this and only enable the RX task
when we have switched on encryption (for 2.1 with SSP). This might fix
some issues with the stupid controllers sending ACL packets before
notifying us that the link has switched on encryption.
Anyway, I am really open for suggestions here. I just think that moving
all RX and TX processing into a workqueue might be a bit overkill. And
keep processing events in a tasklet will create code complexity in the
future when adding AMP support.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 2nd version] IrMC sync server support
From: Luiz Augusto von Dentz @ 2010-08-13 7:03 UTC (permalink / raw)
To: Marcel Mol; +Cc: linux-bluetooth
In-Reply-To: <201008122116.o7CLGo4p017361@joshua.mesa.nl>
Hi Marcel,
On Fri, Aug 13, 2010 at 12:09 AM, Marcel Mol <marcel@mesa.nl> wrote:
> A reasonable working IrMC SYNC server (only full phonebook sync support)
> Support for cal and note by just returning nothing.
> ---
> Makefile.am | 3 +
> plugins/irmc.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/main.c | 10 +-
> src/obex.h | 3 +-
> 4 files changed, 521 insertions(+), 2 deletions(-)
> create mode 100644 plugins/irmc.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 73e2f28..a2873f9 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -55,6 +55,9 @@ builtin_modules += pbap
> builtin_sources += plugins/pbap.c plugins/phonebook.h \
> plugins/vcard.h plugins/vcard.c
>
> +builtin_modules += irmc
> +builtin_sources += plugins/irmc.c plugins/phonebook.h
> +
I guess we don't need phonebook.h, it is already listed in
builtin-sources before.
> builtin_modules += syncevolution
> builtin_sources += plugins/syncevolution.c
>
> diff --git a/plugins/irmc.c b/plugins/irmc.c
> new file mode 100644
> index 0000000..fa7f91d
> --- /dev/null
> +++ b/plugins/irmc.c
> @@ -0,0 +1,507 @@
> +/*
> + *
> + * OBEX IrMC Sync Server
> + *
> + * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * 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
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <glib.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <arpa/inet.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include <openobex/obex.h>
> +#include <openobex/obex_const.h>
> +
> +#include "plugin.h"
> +#include "log.h"
> +#include "obex.h"
> +#include "service.h"
> +#include "phonebook.h"
> +#include "mimetype.h"
> +#include "filesystem.h"
> +#include "dbus.h"
> +
> +#define IRMC_CHANNEL 17
> +
> +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> +<record> \
> + <attribute id=\"0x0001\"> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0004\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x0100\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0003\"/> \
> + <uint8 value=\"%u\" name=\"channel\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0008\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0009\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + <uint16 value=\"0x0100\" name=\"version\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0100\"> \
> + <text value=\"%s\" name=\"name\"/> \
> + </attribute> \
> + \
> + <attribute id=\"0x0301\"> \
> + <sequence> \
> + <uint8 value=\"0x01\"/> \
> + </sequence> \
> + </attribute> \
> +</record>"
> +
> +
> +struct aparam_header {
> + uint8_t tag;
> + uint8_t len;
> + uint8_t val[0];
> +} __attribute__ ((packed));
> +
> +#define DID_LEN 18
> +
> +struct irmc_session {
> + struct obex_session *os;
> + struct apparam_field *params;
> + uint16_t entries;
> + GString *buffer;
> + char sn[DID_LEN];
> + char did[DID_LEN];
> + char manu[DID_LEN];
> + char model[DID_LEN];
> +};
> +
> +#define IRMC_TARGET_SIZE 9
> +
> +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> +
> +/*
> + * FIXME:
> + * the IrMC specs state the first vcard should be the owner
> + * vcard. As there is no simple way to collect ownerdetails
> + * just create an empty vcard (which is allowed according to the
> + * specs).
> + */
> +static const char *owner_vcard =
> + "BEGIN:VCARD\r\n"
> + "VERSION:2.1\r\n"
> + "N:\r\n"
> + "TEL:\r\n"
> + "X-IRMX-LUID:0\r\n"
> + "END:VCARD\r\n";
> +
> +static void phonebook_size_result(const char *buffer, size_t bufsize,
> + int vcards, int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("vcards %d", vcards);
> +
> + irmc->params->maxlistcount = vcards;
> +}
> +
> +static void query_result(const char *buffer, size_t bufsize, int vcards,
> + int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *s, *t;
> +
> + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> +
> + /* first add a 'owner' vcard */
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new(owner_vcard);
> + else
> + irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
> +
> + /* loop around buffer and add X-IRMC-LUID attribs */
> + s = buffer;
> + while ((t = strstr(s, "UID:")) != NULL) {
> + /* add upto UID: into buffer */
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + /*
> + * add UID: line into buffer
> + * Not sure if UID is still needed if X-IRMC-LUID is there
> + */
> + s = t;
> + t = strstr(s, "\r\n");
> + t += 2;
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + /* add X-IRMC-LUID with same number as UID */
> + irmc->buffer = g_string_append_len(irmc->buffer,
> + "X-IRMC-LUID:", 12);
> + s += 4; /* point to uid number */
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + s = t;
> + }
> + /* add remaining bit of buffer */
> + irmc->buffer = g_string_append(irmc->buffer, s);
> +
> + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> +}
> +
> +static void *irmc_connect(struct obex_session *os, int *err)
> +{
> + struct irmc_session *irmc;
> + struct apparam_field *param;
> +
> + DBG("");
> +
> + manager_register_session(os);
> +
> + irmc = g_new0(struct irmc_session, 1);
> + irmc->os = os;
> +
> + /*
> + * FIXME:
> + * Ideally get capabilities info here and use that to define
> + * IrMC DID and SN etc parameters.
> + * For now lets used hostname and some 'random' value
> + */
> + gethostname(irmc->did, DID_LEN);
> + strncpy(irmc->sn, "12345", DID_LEN);
> + strncpy(irmc->manu, "obex", DID_LEN);
> + strncpy(irmc->model, "mymodel", DID_LEN);
> +
> + /*
> + * We need to know the number of contact/cal/nt entries
> + * somewhere so why not do it now.
> + */
> + param = g_new0(struct apparam_field, 1);
> + param->maxlistcount = 0; /* to count the number of vcards... */
> + param->filter = 0x200085; /* UID TEL N VERSION */
> + irmc->params = param;
> + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> + irmc);
> +
> + if (err)
> + *err = 0;
> +
> + return irmc;
> +}
> +
> +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> + gboolean *stream, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *type = obex_get_type(os);
> + const char *name = obex_get_name(os);
> + char *path;
> + int ret;
> +
> + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> +
> + path = g_strdup(name);
> + *stream = TRUE;
> +
> + ret = obex_get_stream_start(os, path);
> +
> + g_free(path);
> +
> + return ret;
> +}
> +
> +static void irmc_disconnect(struct obex_session *os, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("");
> +
> + manager_unregister_session(os);
> +
> + if (irmc->params) {
> + if (irmc->params->searchval)
> + g_free(irmc->params->searchval);
> + g_free(irmc->params);
> + }
> + if (irmc->buffer) {
> + string_free(irmc->buffer);
> + irmc->buffer = NULL;
> + }
> +
> + g_free(irmc);
> +}
> +
> +static int irmc_chkput(struct obex_session *os, void *user_data)
> +{
> + DBG("");
> + /* Reject all PUTs */
> + return -EBADR;
> +}
> +
> +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> +{
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + g_string_append_printf(irmc->buffer,
> + "MANU:%s\r\n"
> + "MOD:%s\r\n"
> + "SN:%s\r\n"
> + "PB-TYPE-TX:VCARD2.1\r\n",
> + irmc->manu, irmc->model, irmc->sn);
> +
> + return irmc;
> +}
> +
> +static void *irmc_open_pb(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + GString *mybuf;
> + int ret;
> +
> + if (!g_strcmp0(name, ".vcf")) {
> + /* how can we tell if the vcard count call already finished? */
> + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> + query_result, irmc);
> + if (ret < 0) {
> + DBG("phonebook_pull failed...");
> + goto fail;
> + }
> + return irmc;
> + }
> +
> + if (!g_strcmp0(name, "/info.log")) {
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "DID:%s\r\n",
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount, irmc->did);
> + }
> + else if (!strncmp(name, "/luid/", 6)) {
> + name += 6;
> + if (!g_strcmp0(name, "cc.log")) {
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> + }
> + else {
> + int l = strlen(name);
> + /* FIXME:
> + * Reply the same to any *.log so we hopefully force a
> + * full phonebook dump.
> + * Is IEL:2 ok?
> + */
> + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> + DBG("changelog request, force whole book");
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "SN:%s\r\n"
> + "IEL:2\r\n"
> + "DID:%s\r\n"
> + "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "*\r\n",
> + irmc->sn, irmc->did,
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount);
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> + }
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> +
> + if (!irmc->buffer)
> + irmc->buffer = mybuf;
> + else {
> + irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
> + string_free(mybuf);
> + }
> +
> + return irmc;
> +
> +fail:
> + if (err)
> + *err = ret;
> +
> + return NULL;
> +}
> +
> +static void *irmc_open_cal(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + /* no suport yet. Just return an empty buffer. cal.vcs */
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + return irmc;
> +}
> +
> +static void *irmc_open_nt(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + /* no suport yet. Just return an empty buffer. nt.vnt */
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + return irmc;
> +}
> +
> +static void *irmc_open(const char *name, int oflag, mode_t mode,
> + void *context, size_t *size, int *err)
> +{
> + struct irmc_session *irmc = context;
> + int ret;
> + const char *p;
> +
> + DBG("name %s context %p", name, context);
> + if (oflag != O_RDONLY) {
> + ret = -EPERM;
> + goto fail;
> + }
Since Ive seen this many times we better put a check for NULL name
here otherwise it may crash in the following line.
> + if (strncmp(name, "telecom/", 8) != 0) {
> + ret = -EBADR;
> + goto fail;
> + }
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* [PATCH v2 2/2] Bluetooth: host level Support for Atheros AR300x device
From: Suraj Sumangala @ 2010-08-13 6:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
In-Reply-To: <1281681408-27376-1-git-send-email-suraj@atheros.com>
Implements support for Atheros AR300x Bluetooth chip in
hciattach application. Supports configuration download
and power management configure feature.
---
Makefile.tools | 7 +-
tools/hciattach.8 | 3 +
tools/hciattach.c | 105 ++++++
tools/hciattach.h | 3 +
tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 974 insertions(+), 3 deletions(-)
create mode 100644 tools/hciattach_ar3k.c
diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..e568bd7 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -21,9 +21,10 @@ tools_rfcomm_LDADD = lib/libbluetooth.la
tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
- tools/hciattach_st.c \
- tools/hciattach_ti.c \
- tools/hciattach_tialt.c
+ tools/hciattach_st.c \
+ tools/hciattach_ti.c \
+ tools/hciattach_tialt.c \
+ tools/hciattach_ar3k.c
tools_hciattach_LDADD = lib/libbluetooth.la
tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f443dff..e0e2730 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -86,6 +86,9 @@ Silicon Wave kits
.TP
.B bcsp
Serial adapters using CSR chips with BCSP serial protocol
+.TP
+.B ath3k
+Atheros AR300x based serial Bluetooth device
.RE
Supported IDs are (manufacturer id, product id)
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 8616899..6cc92c1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -657,6 +657,109 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
return 0;
}
+#define SLEEP_ENABLE 1
+#define SLEEP_DISABLE 0
+
+/*
+ * Atheros AR300x specific initialization post callback
+ */
+static int ath3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, u->pm);
+}
+
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+#define HCI_CHG_BAUD_CMD_OCF 0x0C
+
+#define WRITE_BDADDR_CMD_LEN 14
+#define WRITE_BAUD_CMD_LEN 6
+#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN
+
+/*
+ * Atheros AR300x specific initialization and configureation file
+ * download
+ */
+static int ath3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ int r;
+ int baud;
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
+ unsigned char *ptr = cmd + 1;
+ hci_command_hdr *ch = (void *)ptr;
+
+ cmd[0] = HCI_COMMAND_PKT;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -ETIMEDOUT;
+ }
+
+ /* Write BDADDR */
+ if (u->bdaddr) {
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *)(ptr + 4));
+
+ if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
+ WRITE_BDADDR_CMD_LEN) {
+ perror("Failed to write BD_ADDR command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+ perror("Failed to set BD_ADDR\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* Send HCI Reset */
+ cmd[1] = 0x03;
+ cmd[2] = 0x0C;
+ cmd[3] = 0x00;
+
+ r = write(fd, cmd, 4);
+ if (r != 4)
+ return -ETIMEDOUT;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -ETIMEDOUT;
+
+ /* set controller baud rate to user specified value */
+ ptr = cmd + 1;
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_CHG_BAUD_CMD_OCF));
+ ch->plen = 2;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ baud = u->speed/100;
+ ptr[0] = (char)baud;
+ ptr[1] = (char)(baud >> 8);
+
+ if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
+ perror("Failed to write change baud rate command");
+ return -ETIMEDOUT;
+ }
+
+ nanosleep(&tm, NULL);
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
/*
* Silicon Wave specific initialization
* Thomas Moser <thomas.moser@tmoser.ch>
@@ -1104,6 +1207,8 @@ struct uart_t uart[] = {
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800,
FLOW_CTL, DISABLE_PM, NULL, bcm2035 },
+ { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, ath3kinit, ath3kpost },
{ NULL, 0 }
};
diff --git a/tools/hciattach.h b/tools/hciattach.h
index c0b80a1..ca31731 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -38,6 +38,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH3K 5
#define HCI_UART_RAW_DEVICE 0
@@ -49,3 +50,5 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath_configure_sleep(int fd, int sleep_stat);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100644
index 0000000..ffd143f
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define FW_PATH "/lib/firmware/ar3k/"
+
+struct ps_cfg_entry {
+ uint32_t id;
+ uint32_t len;
+ uint8_t *data;
+};
+
+struct ps_entry_type {
+ unsigned char type;
+ unsigned char array;
+};
+
+#define MAX_TAGS 50
+#define PS_HDR_LEN 4
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+
+struct ps_cfg_entry ps_list[MAX_TAGS];
+
+static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
+{
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = len + PS_HDR_LEN;
+ cmd += HCI_COMMAND_HDR_SIZE;
+
+ cmd[0] = ps_op;
+ cmd[1] = index;
+ cmd[2] = index >> 8;
+ cmd[3] = len;
+}
+
+#define PS_EVENT_LEN 100
+
+/*
+ * Send HCI command and wait for command complete event.
+ * The event buffer has to be freed by the caller.
+ */
+static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
+{
+ int err;
+ uint8_t *hci_event;
+ uint8_t pkt_type = HCI_COMMAND_PKT;
+
+ if (len == 0)
+ return len;
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -EILSEQ;
+ if (write(dev, (unsigned char *)cmd, len) != len)
+ return -EILSEQ;
+
+ hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
+ if (!hci_event)
+ return -ENOMEM;
+
+ err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
+ if (err > 0) {
+ *event = hci_event;
+ } else {
+ free(hci_event);
+ return -EILSEQ;
+ }
+
+ return len;
+}
+
+#define HCI_EV_SUCCESS 0x00
+
+static int read_ps_event(uint8_t *event, uint16_t ocf)
+{
+ hci_event_hdr *eh;
+ uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
+
+ event++;
+
+ eh = (void *)event;
+ event += HCI_EVENT_HDR_SIZE;
+
+ if (eh->evt == EVT_CMD_COMPLETE) {
+ evt_cmd_complete *cc = (void *)event;
+
+ event += EVT_CMD_COMPLETE_SIZE;
+
+ if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
+ return 0;
+ else
+ return -EILSEQ;
+ }
+
+ return -EILSEQ;
+}
+
+static int write_cmd(int fd, uint8_t *buffer, int len)
+{
+ uint8_t *event;
+ int err;
+
+ err = send_hci_cmd_sync(fd, buffer, len, &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define PS_WRITE 1
+#define PS_RESET 2
+#define WRITE_PATCH 8
+#define ENABLE_PATCH 11
+
+#define HCI_PS_CMD_HDR_LEN 7
+
+#define PS_RESET_PARAM_LEN 6
+#define HCI_MAX_CMD_SIZE 260
+#define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
+
+#define PS_ID_MASK 0xFF
+
+/* Sends PS commands using vendor specficic HCI commands */
+static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
+{
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ int i;
+
+ switch (opcode) {
+ case ENABLE_PATCH:
+ load_hci_ps_hdr(cmd, opcode, 0, 0x00);
+
+ if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_RESET:
+ load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
+
+ cmd[7] = 0x00;
+ cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
+ cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
+
+ if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_WRITE:
+ for (i = 0; i < ps_param; i++) {
+ load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
+ ps_list[i].id);
+
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
+ ps_list[i].len);
+
+ if (write_cmd(fd, cmd, ps_list[i].len +
+ HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#define __is_delim(ch) ((ch) == ':')
+#define MAX_PREAMBLE_LEN 4
+
+/* Parse PS entry preamble of format [X:X] for main type and subtype */
+static int get_ps_type(char *ptr, int index, char *type, char *sub_type)
+{
+ int i;
+ int delim = FALSE;
+
+ if (index > MAX_PREAMBLE_LEN)
+ return -EILSEQ;
+
+ for (i = 1; i < index; i++) {
+ if (__is_delim(ptr[i])) {
+ delim = TRUE;
+ continue;
+ }
+
+ if (isalpha(ptr[i])) {
+ if (delim == FALSE)
+ (*type) = toupper(ptr[i]);
+ else
+ (*sub_type) = toupper(ptr[i]);
+ }
+ }
+
+ return 0;
+}
+
+#define ARRAY 'A'
+#define STRING 'S'
+#define DECIMAL 'D'
+#define BINARY 'B'
+
+#define PS_HEX 0
+#define PS_DEC 1
+
+static int get_input_format(char *buf, struct ps_entry_type *format)
+{
+ char *ptr = NULL;
+ char type = '\0';
+ char sub_type = '\0';
+
+ format->type = PS_HEX;
+ format->array = TRUE;
+
+ if (strstr(buf, "[") != buf)
+ return 0;
+
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return -EILSEQ;
+
+ if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
+ return -EILSEQ;
+
+ /* Check is data type is of array */
+ if (type == ARRAY || sub_type == ARRAY)
+ format->array = TRUE;
+
+ if (type == STRING || sub_type == STRING)
+ format->array = FALSE;
+
+ if (type == DECIMAL || type == BINARY)
+ format->type = PS_DEC;
+ else
+ format->type = PS_HEX;
+
+ return 0;
+}
+
+#define UNDEFINED 0xFFFF
+
+static unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
+{
+ char *ptr = buf;
+
+ if (!buf)
+ return UNDEFINED;
+
+ if (buf == strstr(buf, "[")) {
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return UNDEFINED;
+
+ ptr++;
+ }
+
+ if (type.type == PS_HEX && type.array != TRUE)
+ return strtol(ptr, NULL, 16);
+
+ return UNDEFINED;
+}
+
+struct tag_info {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+static inline int update_char_count(const char *buf)
+{
+ char *end_ptr;
+
+ if (strstr(buf, "[") == buf) {
+ end_ptr = strstr(buf, "]");
+ if (!end_ptr)
+ return 0;
+ else
+ return (end_ptr - buf) + 1;
+ }
+
+ return 0;
+}
+
+/* Read PS entries as string, convert and add to Hex array */
+static void update_tag_data(struct ps_cfg_entry *tag,
+ struct tag_info *info, const char *ptr)
+{
+ char buf[3];
+
+ buf[2] = '\0';
+
+ strncpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+
+ strncpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+}
+
+#define PS_UNDEF 0
+#define PS_ID 1
+#define PS_LEN 2
+#define PS_DATA 3
+
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+#define ENTRY_PER_LINE 16
+
+#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
+#define __skip_space(str) while (*(str) == ' ') ((str)++)
+
+static int ath_parse_ps(FILE *stream)
+{
+ char buf[LINE_SIZE_MAX + 1];
+ char *ptr;
+ uint8_t tag_cnt = 0;
+ int16_t byte_count = 0;
+ struct ps_entry_type format;
+ struct tag_info status = { 0, 0, 0, 0 };
+
+ do {
+ int read_count;
+ struct ps_cfg_entry *tag;
+
+ ptr = fgets(buf, LINE_SIZE_MAX, stream);
+ if (!ptr)
+ break;
+
+ __skip_space(ptr);
+ if (__check_comment(ptr))
+ continue;
+
+ /* Lines with a '#' will be followed by new PS entry */
+ if (ptr == strstr(ptr, "#")) {
+ if (status.section != PS_UNDEF) {
+ return -EILSEQ;
+ } else {
+ status.section = PS_ID;
+ continue;
+ }
+ }
+
+ tag = &ps_list[tag_cnt];
+
+ switch (status.section) {
+ case PS_ID:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ tag->id = read_data_in_section(ptr, format);
+ status.section = PS_LEN;
+ break;
+
+ case PS_LEN:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ byte_count = read_data_in_section(ptr, format);
+ if (byte_count > PS_MAX_LEN)
+ return -EILSEQ;
+
+ tag->len = byte_count;
+ tag->data = (uint8_t *)malloc(byte_count);
+
+ status.section = PS_DATA;
+ status.line_count = 0;
+ break;
+
+ case PS_DATA:
+ if (status.line_count == 0)
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ __skip_space(ptr);
+
+ status.char_cnt = update_char_count(ptr);
+
+ read_count = (byte_count > ENTRY_PER_LINE) ?
+ ENTRY_PER_LINE : byte_count;
+
+ if (format.type == PS_HEX && format.array == TRUE) {
+ while (read_count > 0) {
+ update_tag_data(tag, &status, ptr);
+ read_count -= 2;
+ }
+
+ if (byte_count > ENTRY_PER_LINE)
+ byte_count -= ENTRY_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ status.line_count++;
+
+ if (byte_count == 0)
+ memset(&status, 0x00, sizeof(struct tag_info));
+
+ if (status.section == PS_UNDEF)
+ tag_cnt++;
+
+ if (tag_cnt == MAX_TAGS)
+ return -EILSEQ;
+ break;
+ }
+ } while (ptr);
+
+ return tag_cnt;
+}
+
+#define MAX_PATCH_CMD 244
+struct patch_entry {
+ int16_t len;
+ uint8_t data[MAX_PATCH_CMD];
+};
+
+static int ps_patch_download(int fd, FILE *stream)
+{
+ char byte[3];
+ char ptr[MAX_PATCH_CMD + 1];
+ int byte_cnt;
+ int patch_count = 0;
+
+ byte[2] = '\0';
+
+ while (fgets(ptr, MAX_PATCH_CMD, stream)) {
+ if (strlen(ptr) <= 1 || !isxdigit(ptr[0]))
+ continue;
+ else
+ break;
+ }
+
+ byte_cnt = strtol(ptr, NULL, 16);
+
+ while (byte_cnt > 0) {
+ int i;
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ struct patch_entry patch;
+
+ if (byte_cnt > MAX_PATCH_CMD)
+ patch.len = MAX_PATCH_CMD;
+ else
+ patch.len = byte_cnt;
+
+ for (i = 0; i < patch.len; i++) {
+ if (!fgets(byte, 3, stream))
+ return -1;
+
+ patch.data[i] = strtoul(byte, NULL, 16);
+ }
+
+ load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
+
+ if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
+ return -1;
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_PATCH_CMD;
+ }
+
+ if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
+ return -1;
+
+ return patch_count;
+}
+
+#define PS_RAM_SIZE 2048
+
+static int ps_config_download(int fd, int tag_count)
+{
+
+ if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
+ return -1;
+
+ if (tag_count > 0)
+ if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
+ return -1;
+ return 0;
+}
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+
+static void get_ps_file_name(int devtype, int rom_version, char *path)
+{
+ char *filename;
+
+ if (devtype == 0xdeadc0de)
+ filename = PS_ASIC_FILE;
+ else
+ filename = PS_FPGA_FILE;
+
+ snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
+}
+
+#define PATCH_FILE "RamPatch.txt"
+#define FPGA_ROM_VERSION 0x99999999
+#define ROM_DEV_TYPE 0xdeadc0de
+
+static void get_patch_file_name(int dev_type, int rom_version,
+ int build_version, char *path)
+{
+
+ if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
+ dev_type != 0 && build_version == 1)
+ path[0] = '\0';
+ else
+ snprintf(path, MAXPATHLEN, "%s%x/%s",
+ FW_PATH, rom_version, PATCH_FILE);
+}
+
+#define VERIFY_CRC 9
+#define PS_REGION 1
+#define PATCH_REGION 2
+
+static int get_ar3k_crc(int dev)
+{
+ uint8_t cmd[7];
+ uint8_t *event;
+ int err;
+
+ load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+ /* Send error code if CRC check patched */
+ if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
+ err = -EILSEQ;
+
+ if (!event)
+ free(event);
+
+ return err;
+}
+
+#define DEV_REGISTER 0x4FFC
+#define GET_DEV_TYPE_OCF 0x05
+
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t cmd[8];
+ uint8_t *event;
+ uint32_t reg;
+ int err;
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ GET_DEV_TYPE_OCF));
+ ch->plen = 5;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = (uint8_t)DEV_REGISTER;
+ ptr[1] = (uint8_t)DEV_REGISTER >> 8;
+ ptr[2] = (uint8_t)DEV_REGISTER >> 16;
+ ptr[3] = (uint8_t)DEV_REGISTER >> 24;
+ ptr[4] = 0x04;
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, GET_DEV_TYPE_OCF);
+ if (err < 0)
+ goto cleanup;
+
+ reg = event[10];
+ reg = (reg << 8) | event[9];
+ reg = (reg << 8) | event[8];
+ reg = (reg << 8) | event[7];
+ *code = reg;
+
+cleanup:
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define GET_VERSION_OCF 0x1E
+
+static int read_ar3k_version(int pConfig, int *rom_version, int *build_version)
+{
+ uint8_t cmd[3];
+ uint8_t *event;
+ int err;
+ int status;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ GET_VERSION_OCF));
+ ch->plen = 0;
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, GET_VERSION_OCF);
+ if (err < 0)
+ goto cleanup;
+
+ status = event[10];
+ status = (status << 8) | event[9];
+ status = (status << 8) | event[8];
+ status = (status << 8) | event[7];
+ *rom_version = status;
+
+ status = event[14];
+ status = (status << 8) | event[13];
+ status = (status << 8) | event[12];
+ status = (status << 8) | event[11];
+ *build_version = status;
+
+cleanup:
+ if (event)
+ free(event);
+
+ return err;
+}
+
+static void convert_bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ int colon_present = 0;
+
+ if (strstr(str_bdaddr, ":"))
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ /* Reverse the BDADDR to LSB first */
+ for (i = 0, j = 5; i < 6; i++, j--) {
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t *event;
+ int err;
+ uint8_t cmd[13];
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ memset(cmd, 0, sizeof(cmd));
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+
+ convert_bdaddr(bdaddr, (char *)&ptr[4]);
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define HCI_SLEEP_CMD_OCF 0x04
+
+int ath_configure_sleep(int fd, int sleep_stat)
+{
+ int dev_id, dd;
+ struct timespec tm = { 0, 50000 };
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return dev_id;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return dd;
+ }
+
+ sleep(2);
+
+ /* send vendor specific command with Sleep feature Enabled */
+ if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF,
+ 1, &sleep_stat) < 0)
+ perror("Power management Disabled");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+static void write_bdaddr_from_file(int rom_version, int fd)
+{
+ FILE *stream;
+ char bdaddr[PATH_MAX];
+ char bdaddr_file[PATH_MAX];
+
+ snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
+ FW_PATH, rom_version, BDADDR_FILE);
+
+ stream = fopen(bdaddr_file, "r");
+ if (!stream)
+ return;
+
+ if (fgets(bdaddr, PATH_MAX - 1, stream))
+ write_bdaddr(fd, bdaddr);
+
+ fclose(stream);
+}
+
+int ath_ps_download(int fd)
+{
+ int err = 0;
+ int tag_count;
+ int patch_count = 0;
+ int rom_version = 0;
+ int build_version = 0;
+ uint32_t dev_type = 0;
+ char patch_file[PATH_MAX];
+ char ps_file[PATH_MAX];
+ FILE *stream;
+
+ /*
+ * Verfiy firmware version. depending on it select the PS
+ * config file to download.
+ */
+ if (get_device_type(fd, &dev_type) < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ if (read_ar3k_version(fd, &rom_version, &build_version) < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ /* Do not download configuration if CRC passes */
+ if (get_ar3k_crc(fd) < 0) {
+ err = 0;
+ goto download_cmplete;
+ }
+
+ get_ps_file_name(dev_type, rom_version, ps_file);
+ get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+
+ stream = fopen(ps_file, "r");
+ if (!stream) {
+ perror("firmware file open error\n");
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+ tag_count = ath_parse_ps(stream);
+
+ fclose(stream);
+
+ if (tag_count < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if patch file is not available.
+ */
+ if (patch_file[0] == '\0')
+ err = 0;
+
+ stream = fopen(patch_file, "r");
+ if (!stream)
+ err = 0;
+ else {
+ patch_count = ps_patch_download(fd, stream);
+ fclose(stream);
+
+ if (patch_count < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+ }
+
+ err = ps_config_download(fd, tag_count);
+
+download_cmplete:
+ if (!err)
+ write_bdaddr_from_file(rom_version, fd);
+
+ return err;
+}
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 1/2] Bluetooth: Option to enable power management from host
From: Suraj Sumangala @ 2010-08-13 6:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
This provides a new option for hciattach to enable hardware specific
power management from host.
This option by default will be disabled for existing devices
---
tools/hciattach.8 | 13 ++++++++
tools/hciattach.c | 88 ++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 76 insertions(+), 25 deletions(-)
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index 9bd1538..f443dff 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -122,7 +122,20 @@ the serial link (
set by default. To force no flow control use
.B noflow
instead.
+.TP
+.I sleep
+Enables hardware specific power management feature. If
+.I sleep
+is appended to the list of options then this feature is enabled. To disable
+this feature use
+.B nosleep
+instead.
+All above mentioned device types have
+.B nosleep
+set by default.
+Note: This option will only be valid for hardware which support
+hardware specific power management enable option from host.
.TP
.I bdaddr
The
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 81aea7b..8616899 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -63,12 +63,15 @@ struct uart_t {
int init_speed;
int speed;
int flags;
+ int pm;
char *bdaddr;
int (*init) (int fd, struct uart_t *u, struct termios *ti);
int (*post) (int fd, struct uart_t *u, struct termios *ti);
};
#define FLOW_CTL 0x0001
+#define ENABLE_PM 1
+#define DISABLE_PM 0
static volatile sig_atomic_t __io_canceled = 0;
@@ -1006,72 +1009,100 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
}
struct uart_t uart[] = {
- { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
- { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, ericsson },
- { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, FLOW_CTL, NULL, digi },
+ { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
- { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, ericsson },
+
+ { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, digi },
+
+ { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter */
- { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */
- { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+ { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* BrainBoxes PCMCIA card (BL620) */
- { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, csr },
+ { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* Silicon Wave kits */
- { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, swave },
+ { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, swave },
/* Texas Instruments Bluelink (BRF) modules */
- { "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texas, texas2 },
- { "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texasalt, NULL },
+ { "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, texas, texas2 },
+
+ { "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, texasalt, NULL },
/* ST Microelectronics minikits based on STLC2410/STLC2415 */
- { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, st },
+ { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, st },
/* ST Microelectronics minikits based on STLC2500 */
- { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "00:80:E1:00:AB:BA", stlc2500 },
+ { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, "00:80:E1:00:AB:BA", stlc2500 },
/* Philips generic Ericsson IP core based */
- { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* Philips BGB2xx Module */
- { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "BD:B2:10:00:AB:BA", bgb2xx },
+ { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, "BD:B2:10:00:AB:BA", bgb2xx },
/* Sphinx Electronics PICO Card */
- { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* Inventel BlueBird Module */
- { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* COM One Platinium Bluetooth PC Card */
- { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* TDK Bluetooth PC Card and IBM Bluetooth PC Card II */
- { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Socket Bluetooth CF Card (Rev G) */
- { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, 0, NULL, bcsp },
+ { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400,
+ 0, DISABLE_PM, NULL, bcsp },
/* 3Com Bluetooth Card (Version 3.0) */
- { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+ { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* AmbiCom BT2000C Bluetooth PC/CF Card */
- { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, FLOW_CTL, NULL, csr },
+ { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* Zoom Bluetooth PCMCIA Card */
- { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Sitecom CN-504 PCMCIA Card */
- { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Billionton PCBTC1 PCMCIA Card */
- { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Broadcom BCM2035 */
- { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+ { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, bcm2035 },
{ NULL, 0 }
};
@@ -1290,6 +1321,13 @@ int main(int argc, char *argv[])
break;
case 4:
+ if (!strcmp("sleep", argv[optind]))
+ u->pm = ENABLE_PM;
+ else
+ u->pm = DISABLE_PM;
+ break;
+
+ case 5:
u->bdaddr = argv[optind];
break;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH] Fix unnecessary checking for empty phones list
From: Radoslaw Jablonski @ 2010-08-13 6:35 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Removed not needed anymore checking for empty list of phone numbers.
---
plugins/vcard.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 9beb62a..80f8265 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -295,11 +295,6 @@ static void vcard_printf_end(GString *vcards)
void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
uint64_t filter, uint8_t format)
{
- /* There's really nothing to do */
- if ((contact->numbers == NULL && (contact->fullname == NULL ||
- contact->fullname[0] == '\0')))
- return;
-
if (format == FORMAT_VCARD30)
filter |= (FILTER_VERSION | FILTER_FN | FILTER_N | FILTER_TEL);
else if (format == FORMAT_VCARD21)
--
1.7.0.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox