* [PATCH 1/4] Constants for L2CAP and AMP extensions
From: Inga Stotland @ 2010-07-30 18:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel, Inga Stotland
In-Reply-To: <1280514626-22559-1-git-send-email-ingas@codeaurora.org>
---
lib/l2cap.h | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/lib/l2cap.h b/lib/l2cap.h
index e59cfdd..2f1084c 100644
--- a/lib/l2cap.h
+++ b/lib/l2cap.h
@@ -35,6 +35,8 @@ extern "C" {
/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
+#define L2CAP_DEFAULT_TX_WINDOW 63
+#define L2CAP_DEFAULT_MAX_TX 3
/* L2CAP socket address */
struct sockaddr_l2 {
@@ -44,6 +46,12 @@ struct sockaddr_l2 {
unsigned short l2_cid;
};
+/* L2CAP fixed channel CIDs */
+#define L2CAP_SIGNAL_CHAN_CID 0x0001
+#define L2CAP_CONNECTIONLESS_CID 0x0002
+#define L2CAP_AMP_MGR_CID 0x0003
+#define L2CAP_AMP_TEST_CID 0x003F
+
/* L2CAP socket options */
#define L2CAP_OPTIONS 0x01
struct l2cap_options {
@@ -69,6 +77,12 @@ struct l2cap_conninfo {
#define L2CAP_LM_TRUSTED 0x0008
#define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020
+#define L2CAP_LM_FLUSHABLE 0x0040
+
+#define L2CAP_AMP 0x04
+#define L2CAP_AMP_REQUIRE_BR_EDR 0x01
+#define L2CAP_AMP_PREFER_AMP 0x02
+#define L2CAP_AMP_PREFER_BR_EDR 0x03
/* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01
--
1.7.2
--
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related
* Enhancements to allow l2cap channel to use either AMP or BR/EDR
From: Inga Stotland @ 2010-07-30 18:30 UTC (permalink / raw)
To: linux-bluetooth; +Cc: rshaffer, johan.hedberg, marcel
AMP vs BR/EDR preference for L2CAP channel can be configured as
command line argument using new option "-J". Possible values:
"require_br_edr",
"prefer_amp",
"prefer_br_edr"
If no preference indicated, the default is set to require BR/EDR.
Additionally, this option can be changed during runtime when L2CAP
connection is up by entering the following keys from standard input:
"a", "A" - prefer AMP;
"b", "B" - prefer BR/EDR;
"r", "R" - require BR/EDR
This allows dynamic L2CAP channel move between BR/EDR and AMP.
--
Inga Stotland
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* Re: obexd 0.29 and N900 PC Suite
From: Luiz Augusto von Dentz @ 2010-07-30 15:08 UTC (permalink / raw)
To: Harald Schmitt; +Cc: Marcel J.E. Mol, linux-bluetooth
In-Reply-To: <4C52A995.8080205@hschmitt.de>
Hi,
On Fri, Jul 30, 2010 at 1:29 PM, Harald Schmitt <linux@hschmitt.de> wrote:
> I have testes following command and it seems to work:
> dbus-send --system --type=signal / com.meego.usb_moded.sig_usb_state_ind
> string:'ovi_suite'
> If one would just add this line to pcsuite-enable.sh under the SIGUSR1 then
> both types of obexd would work?
> Luiz could you confirm this? Do we also need a dbus-command for disconnect
> with string:'USB disconnected' in pcsuite-disable.sh?
Hmm it may work with that but I would first just revert the patch I
suggest other day since without that part there could be some other
components still sending SIGUSR1 to obexd which might kill it, maybe I
can just reintroduce SIGUSR1 and then have a config option saying
which method to use for usb cable detection. What do you guys think?
In future I really want a standard way to do the cable detection, I
guess udev + libusb could be a better alternative.
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* Re: Problem connecting headset with bluez >= 4.64
From: Michal 'vorner' Vaner @ 2010-07-30 14:01 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <20100712124827.GA3012@hydra.kolej.mff.cuni.cz>
Hello
On Mon, Jul 12, 2010 at 02:48:27PM +0200, Michal 'vorner' Vaner wrote:
> I have a bluetooth headset/headphones. However, I have a problem to connect to
> them on one of my machines (while other two machines work well). Downgrading to
> version 4.63 helps. In that case, bluetooth outputs something like this (this is
> for the HSP profile, the A2DP acts similarly):
>
> [ .... Deleted logs .... ]
>
> I tried bisecting the sources and it seems the problem is introduced in commit
> aee26b30bbc24cde464ba1a557c2b258ddec6432 "Make BtIO default security level
> MEDIUM". When I compile version with all commits up to master except this one,
> it works, so this confirms my problem comes from this commit.
>
> A wild guess is that the machines differ in which adapter they have and that
> this one does not support something needed for the medium level security. The
> adaptor is "OMEGA MICRO BT140", while the other two computers are laptops and
> have some onboard usb connected adaptors (I do not know which ones). Is it
> possible? If so, is there a possibility forcing bluez not using the
> not-implemented function in a cleaner way than omitting the commit?
I found out that it works with different dongle on the same computer. Is it bug
in the dongle or something that could be fixed in software too?
Thanks
--
I've already told you more than I know.
Michal 'vorner' Vaner
^ permalink raw reply
* Re: [PATCH] Bluetooth: Don't send RFC for Basic Mode if only it is supported
From: Ville Tervo @ 2010-07-30 13:13 UTC (permalink / raw)
To: ext Gustavo F. Padovan
Cc: linux-bluetooth@vger.kernel.org, Gustavo F. Padovan
In-Reply-To: <1280426444-20469-1-git-send-email-gustavo@padovan.org>
Hi,
On 07/29/2010 09:00 PM, ext Gustavo F. Padovan wrote:
> From: Gustavo F. Padovan<padovan@profusion.mobi>
>
> If the remote side doesn't support Enhanced Retransmission Mode neither
> Streaming Mode, we shall not send the RFC option.
> Some devices that only supports Basic Mode do not understanding the RFC
> option. This patch fix the regression found with that devices.
Yes this is better. After some research i found out that quite many old
devices are not handling properly unknown options.
However I found another regression. And this kind of patch is needed
also. Otherwise the info rsp code is reading feat_mask from failed
response (and does invalid memory access).
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 0f34e12..1e174a4 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3348,6 +3348,13 @@ static inline int l2cap_information_rsp(struct
l2cap_conn *conn, struct l2cap_cm
del_timer(&conn->info_timer);
+ if (result != L2CAP_IR_SUCCESS) {
+ conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+ conn->info_ident = 0;
+ l2cap_conn_start(conn);
+ return 0;
+ }
+
if (type == L2CAP_IT_FEAT_MASK) {
conn->feat_mask = get_unaligned_le32(rsp->data);
--
Ville
^ permalink raw reply related
* Re: obexd 0.29 and N900 PC Suite
From: Harald Schmitt @ 2010-07-30 10:29 UTC (permalink / raw)
To: Marcel J.E. Mol; +Cc: linux-bluetooth, Luiz Augusto von Dentz
In-Reply-To: <20100729181649.GA9339@joshua.mesa.nl>
Am 29.07.2010 20:16, schrieb Marcel J.E. Mol:
> On Thu, Jul 29, 2010 at 05:36:48PM +0200, Harald Schmitt wrote:
>> Hi,
>>
>> Am 27.07.2010 15:03, schrieb Luiz Augusto von Dentz:
>>
>> Hi,
>>
>> On Tue, Jul 27, 2010 at 2:27 PM, Harald Schmitt<linux@xxxxxxxxxxx> wrote:
>>
>> Hi,
>>
>> there are several users who test obexd 0.29 on the Nokia N900 running Maemo
>> in order to have PBAP support. There are success reports with PBAP, but at
>> the same time they cannot usb sync via Nokia PC Suite anymore. Is there any
>> chance to get PC Suite working again in a future obexd version or does this
>> depend on a non free Nokia code?
>> Can you give any hints where to look at?
>> In a forum a user posted success (with 0.19) and failure (with 0.29) logs:
>> http://talk.maemo.org/showthread.php?p=763550#post763550
>>
>> First thanks a lot for this feedback, I wasn't aware that there were
>> somebody trying to use newer version of obexd in N900, I will take a
>> look how I can make usb compatible with N900, actually it should be
>> just as bluetooth and work no matter which platform you are using but
>> we are not there yet :(
>>
>> In the meantime you can try reverting the patch bellow and see if it helps:
>>
>> http://git.kernel.org/?p=bluetooth/obexd.git;a=commitdiff;h=6f56a4355585eb29535782f977ba545cc41dd382
>>
>> Thanks for the hint. I built a package from 0.29, the patches from meego.gitorious.org and the reverted patch. Some from the community tested it and PC Suite via USB did work. Of course obexd had to be started with the added option "--capability !/usr/bin/gen-obex-capability.sh".
>>
>
> It seems the patch revert a conversion from unix signaling to dbus signaling.
> The pcsuite-enable.sh script uses a unix signal to tell obexd a pcsuite
> connection is requested.
> Apperantly in meego this will be done using dbus..
>
> Can't we convert pcsuite-enable.sh to also use dbus instead of reverting
> the patch? Can you help us out her Luiz?
>
I have testes following command and it seems to work:
dbus-send --system --type=signal / com.meego.usb_moded.sig_usb_state_ind
string:'ovi_suite'
If one would just add this line to pcsuite-enable.sh under the SIGUSR1
then both types of obexd would work?
Luiz could you confirm this? Do we also need a dbus-command for
disconnect with string:'USB disconnected' in pcsuite-disable.sh?
--
Harald
^ permalink raw reply
* Re: obexd 0.29 and N900 PC Suite
From: Marcel J.E. Mol @ 2010-07-29 18:16 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <AANLkTi=WSgMe86k-h=_HdzsPTZ=rK5ab5O9mYf8C6jnc@xxxxxxxxxxxxxx>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset*=utf-8''%E2%80%9Cus-ascii, Size: 2486 bytes --]
On Thu, Jul 29, 2010 at 05:36:48PM +0200, Harald Schmitt wrote:
> Hi,
>
> Am 27.07.2010 15:03, schrieb Luiz Augusto von Dentz:
>
> Hi,
>
> On Tue, Jul 27, 2010 at 2:27 PM, Harald Schmitt<linux@xxxxxxxxxxx> wrote:
>
> Hi,
>
> there are several users who test obexd 0.29 on the Nokia N900 running Maemo
> in order to have PBAP support. There are success reports with PBAP, but at
> the same time they cannot usb sync via Nokia PC Suite anymore. Is there any
> chance to get PC Suite working again in a future obexd version or does this
> depend on a non free Nokia code?
> Can you give any hints where to look at?
> In a forum a user posted success (with 0.19) and failure (with 0.29) logs:
> http://talk.maemo.org/showthread.php?p=763550#post763550
>
> First thanks a lot for this feedback, I wasn't aware that there were
> somebody trying to use newer version of obexd in N900, I will take a
> look how I can make usb compatible with N900, actually it should be
> just as bluetooth and work no matter which platform you are using but
> we are not there yet :(
>
> In the meantime you can try reverting the patch bellow and see if it helps:
>
> http://git.kernel.org/?p=bluetooth/obexd.git;a=commitdiff;h=6f56a4355585eb29535782f977ba545cc41dd382
>
> Thanks for the hint. I built a package from 0.29, the patches from meego.gitorious.org and the reverted patch. Some from the community tested it and PC Suite via USB did work. Of course obexd had to be started with the added option "--capability !/usr/bin/gen-obex-capability.sh".
>
> --
> Harald Schmitt
It seems the patch revert a conversion from unix signaling to dbus signaling.
The pcsuite-enable.sh script uses a unix signal to tell obexd a pcsuite
connection is requested.
Apperantly in meego this will be done using dbus..
Can't we convert pcsuite-enable.sh to also use dbus instead of reverting
the patch? Can you help us out her Luiz?
-Marcel
--
======-------- 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: Don't send RFC for Basic Mode if only it is supported
From: Gustavo F. Padovan @ 2010-07-29 18:04 UTC (permalink / raw)
To: linux-bluetooth; +Cc: ville.tervo
In-Reply-To: <1280426444-20469-1-git-send-email-gustavo@padovan.org>
Hi Ville,
* Gustavo F. Padovan <gustavo@padovan.org> [2010-07-29 15:00:44 -0300]:
> From: Gustavo F. Padovan <padovan@profusion.mobi>
>
> If the remote side doesn't support Enhanced Retransmission Mode neither
> Streaming Mode, we shall not send the RFC option.
> Some devices that only supports Basic Mode do not understanding the RFC
> option. This patch fix the regression found with that devices.
>
> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
> ---
> net/bluetooth/l2cap.c | 15 ++++++++++++---
> 1 files changed, 12 insertions(+), 3 deletions(-)
Could you please test this patch, I'm pretty sure that it fixes the
issue with Nokia 9300.
>
> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
> index 9ba1e8e..0f34e12 100644
> --- a/net/bluetooth/l2cap.c
> +++ b/net/bluetooth/l2cap.c
> @@ -2527,6 +2527,10 @@ done:
> if (pi->imtu != L2CAP_DEFAULT_MTU)
> l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
>
> + if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) &&
> + !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING))
> + break;
> +
> rfc.mode = L2CAP_MODE_BASIC;
> rfc.txwin_size = 0;
> rfc.max_transmit = 0;
> @@ -2534,6 +2538,8 @@ done:
> rfc.monitor_timeout = 0;
> rfc.max_pdu_size = 0;
>
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> break;
>
> case L2CAP_MODE_ERTM:
> @@ -2546,6 +2552,9 @@ done:
> if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
> rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
>
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> +
> if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
> break;
>
> @@ -2566,6 +2575,9 @@ done:
> if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
> rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
>
> + l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> + (unsigned long) &rfc);
> +
> if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
> break;
>
> @@ -2577,9 +2589,6 @@ done:
> break;
> }
>
> - l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
> - (unsigned long) &rfc);
> -
> /* FIXME: Need actual value of the flush timeout */
> //if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
> // l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
> --
> 1.7.1.1
>
--
Gustavo F. Padovan
http://padovan.org
^ permalink raw reply
* [PATCH] Bluetooth: Don't send RFC for Basic Mode if only it is supported
From: Gustavo F. Padovan @ 2010-07-29 18:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Gustavo F. Padovan
In-Reply-To: <4C5020D7.7080005@nokia.com>
From: Gustavo F. Padovan <padovan@profusion.mobi>
If the remote side doesn't support Enhanced Retransmission Mode neither
Streaming Mode, we shall not send the RFC option.
Some devices that only supports Basic Mode do not understanding the RFC
option. This patch fix the regression found with that devices.
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
---
net/bluetooth/l2cap.c | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index 9ba1e8e..0f34e12 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -2527,6 +2527,10 @@ done:
if (pi->imtu != L2CAP_DEFAULT_MTU)
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu);
+ if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) &&
+ !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING))
+ break;
+
rfc.mode = L2CAP_MODE_BASIC;
rfc.txwin_size = 0;
rfc.max_transmit = 0;
@@ -2534,6 +2538,8 @@ done:
rfc.monitor_timeout = 0;
rfc.max_pdu_size = 0;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
break;
case L2CAP_MODE_ERTM:
@@ -2546,6 +2552,9 @@ done:
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+
if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@ -2566,6 +2575,9 @@ done:
if (L2CAP_DEFAULT_MAX_PDU_SIZE > pi->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10);
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+ (unsigned long) &rfc);
+
if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS))
break;
@@ -2577,9 +2589,6 @@ done:
break;
}
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
- (unsigned long) &rfc);
-
/* FIXME: Need actual value of the flush timeout */
//if (flush_to != L2CAP_DEFAULT_FLUSH_TO)
// l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, 2, pi->flush_to);
--
1.7.1.1
^ permalink raw reply related
* Re: obexd 0.29 and N900 PC Suite
From: Harald Schmitt @ 2010-07-29 15:36 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <AANLkTi=WSgMe86k-h=_HdzsPTZ=rK5ab5O9mYf8C6jnc@mail.gmail.com>
Hi,
Am 27.07.2010 15:03, schrieb Luiz Augusto von Dentz:
> Hi,
>
> On Tue, Jul 27, 2010 at 2:27 PM, Harald Schmitt<linux@hschmitt.de> wrote:
>> Hi,
>>
>> there are several users who test obexd 0.29 on the Nokia N900 running Maemo
>> in order to have PBAP support. There are success reports with PBAP, but at
>> the same time they cannot usb sync via Nokia PC Suite anymore. Is there any
>> chance to get PC Suite working again in a future obexd version or does this
>> depend on a non free Nokia code?
>> Can you give any hints where to look at?
>> In a forum a user posted success (with 0.19) and failure (with 0.29) logs:
>> http://talk.maemo.org/showthread.php?p=763550#post763550
>
> First thanks a lot for this feedback, I wasn't aware that there were
> somebody trying to use newer version of obexd in N900, I will take a
> look how I can make usb compatible with N900, actually it should be
> just as bluetooth and work no matter which platform you are using but
> we are not there yet :(
>
> In the meantime you can try reverting the patch bellow and see if it helps:
>
> http://git.kernel.org/?p=bluetooth/obexd.git;a=commitdiff;h=6f56a4355585eb29535782f977ba545cc41dd382
>
Thanks for the hint. I built a package from 0.29, the patches from
meego.gitorious.org and the reverted patch. Some from the community
tested it and PC Suite via USB did work. Of course obexd had to be
started with the added option "--capability
!/usr/bin/gen-obex-capability.sh".
--
Harald Schmitt
^ permalink raw reply
* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Manuel Naranjo @ 2010-07-29 13:34 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: Johan Hedberg, BlueZ
In-Reply-To: <AANLkTi=9Top+9kRwtZj-nZw8szQU4ff9CTSNSGuexmEL@mail.gmail.com>
Luiz,
> I guess I finally figure out what could be the source of your
> problems, we are not removing the watches when caching the session and
> since the context is already freed bt_cancel_discovery doesn't work.
>
> The attached patch should fix this problem, Im also reseting the
> internal data of the session by doing sdp_set_notify so if we are not
> closing the session it will then reset the callback and data to NULL.
>
Looks like a possible fix nice work thanks!.
Unfortunately I will not be able to test until next week. I let you know
when I get some results, I got my netbook today in a mall with some more
debug messages, I added a few calls to error in the search_cb that
prints all the pointer numbers when it gets called, that will get some
more information. I could fix the problem this way as well, but this is
working on the simpthon not on the cause like yours.
You think the hole problem is because of the cache? Wow I never thought
it that way. But it makes sense. It also makes sense to move cleanup
processes inside the cleanup function.
I will give this a try and let you know. Maybe I can results before the
Tuesday, but I doubt it.
Manuel
^ permalink raw reply
* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Luiz Augusto von Dentz @ 2010-07-29 8:53 UTC (permalink / raw)
To: Manuel Naranjo; +Cc: Johan Hedberg, BlueZ
In-Reply-To: <AANLkTikRQfhAKm-UW+on+ZeEp709z_ku_NDjeVD_US1b@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 5605 bytes --]
Hi Manuel,
On Wed, Jul 28, 2010 at 9:46 PM, Manuel Naranjo <manuel@aircable.net> wrote:
> Luiz,
>
> Bad news it doesn't work, it keeps doing the same. This is the output
> of bluetoothd -n -d:
> bluetoothd[3572]: audio/manager.c:handle_uuid() server not enabled for
> 0000110a-0000-1000-8000-00805f9b34fb (0x110a)
> bluetoothd[3572]: audio/manager.c:handle_uuid() Found AV Target
> bluetoothd[3572]: audio/control.c:control_init() Registered interface
> org.bluez.Control on path /org/bluez/3572/hci0/dev_00_24_91_E4_E9_05
> bluetoothd[3572]: audio/manager.c:handle_uuid() Found AV Target
> bluetoothd[3572]: src/device.c:btd_device_unref() 0x90f9e08: ref=2
> bluetoothd[3572]: src/device.c:btd_device_ref() 0x90f9e08: ref=3
> bluetoothd[3572]: src/device.c:search_cb()
> /org/bluez/3572/hci0/dev_00_24_91_E4_E9_05: No service update
> bluetoothd[3572]: src/device.c:btd_device_unref() 0x90f9e08: ref=2
> bluetoothd[3572]: src/adapter.c:session_unref() 0x90b2790: ref=0
> bluetoothd[3572]: src/adapter.c:session_remove() Discovery session
> 0x90b2790 with :1.81 deactivated
> bluetoothd[3572]: src/adapter.c:session_remove() Stopping discovery
> bluetoothd[3572]: Stopping discovery
> bluetoothd[3572]: src/device.c:btd_device_ref() 0x90adfd0: ref=2
> bluetoothd[3572]: Discovery session 0x90fe178 with :1.81 activated
> bluetoothd[3572]: src/adapter.c:session_ref() 0x90fe178: ref=1
> bluetoothd[3572]: src/adapter.c:adapter_remove_connection() Removing
> temporary device /org/bluez/3572/hci0/dev_C8_7E_75_DC_1E_86
> bluetoothd[3572]: src/device.c:device_remove() Removing device
> /org/bluez/3572/hci0/dev_C8_7E_75_DC_1E_86
> bluetoothd[3572]: src/device.c:btd_device_unref() 0x90fc080: ref=1
> bluetoothd[3572]: src/device.c:btd_device_unref() 0x90fc080: ref=0
> bluetoothd[3572]: src/device.c:device_free() 0x90fc080
> bluetoothd[3572]: src/adapter.c:adapter_get_device() 00:05:4F:63:5A:E0
> bluetoothd[3572]: src/adapter.c:session_unref() 0x90fe178: ref=0
> bluetoothd[3572]: src/adapter.c:session_remove() Discovery session
> 0x90fe178 with :1.81 deactivated
> bluetoothd[3572]: src/adapter.c:session_remove() Stopping discovery
> bluetoothd[3572]: Stopping discovery
> bluetoothd[3572]: Discovery session 0x90b1e00 with :1.81 activated
> bluetoothd[3572]: src/adapter.c:session_ref() 0x90b1e00: ref=1
> bluetoothd[3572]: <27>Jul 28 14:26:36 bluetoothd[3572]: : error
> updating services: Host is down (112)
>
>
> And this is the call trace during the crash:
> + 4 0x80ac636 (from 0x80a9a28) device_remove_connection():
> /home/manuel/bluez/src/device.c:908
> + 5 0x80ac4ca (from 0x80ac753) device_set_connected():
> /home/manuel/bluez/src/device.c:875
> + 6 0x80b0d08 (from 0x80ac517) emit_property_changed():
> /home/manuel/bluez/src/dbus-common.c:266
> + 7 0x80b0a31 (from 0x80b0da4) append_variant():
> /home/manuel/bluez/src/dbus-common.c:195
> + 7 0x805005d (from 0x80b0db6) g_dbus_send_message():
> /home/manuel/bluez/gdbus/object.c:615
> + 4 0x80ae60e (from 0x80a9a55) device_get_address():
> /home/manuel/bluez/src/device.c:1654
> + 5 0x80aa5a4 (from 0x80ae639) bacpy():
> /home/manuel/bluez/./lib/bluetooth/bluetooth.h:132
> + 4 0x808a77f (from 0x80a9a6d) hci_req_queue_remove():
> /home/manuel/bluez/src/security.c:169
> + 4 0x80affea (from 0x80a9a78) device_is_authenticating():
> /home/manuel/bluez/src/device.c:2339
> + 4 0x80ae749 (from 0x80a9a9a) device_is_temporary():
> /home/manuel/bluez/src/device.c:1683
> + 1 0x808a82f (from 0x808cdb4) check_pending_hci_req():
> /home/manuel/bluez/src/security.c:186
> + 0 0x8094781 (from 0x2cddab) connect_cb(): /home/manuel/bluez/src/btio.c:138
> + 1 0x8094628 (from 0x80947be) check_nval():
> /home/manuel/bluez/src/btio.c:103
> + 1 0x8097b6e (from 0x8094849) bt_io_error_quark():
> /home/manuel/bluez/src/btio.c:1296
> + 1 0x8099523 (from 0x80948c1) connect_watch():
> /home/manuel/bluez/src/glib-helper.c:283
> + 2 0x80ae1c5 (from 0x809966f) browse_cb():
> /home/manuel/bluez/src/device.c:1540
> + 3 0x80adf2f (from 0x80ae312) search_cb():
> /home/manuel/bluez/src/device.c:1476
> + 4 0x8089ef6 (from 0x80adf90) error(): /home/manuel/bluez/src/log.c:47
>
>
> If you go through the code it fails in the line:
> static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
> {
> struct browse_req *req = user_data;
> struct btd_device *device = req->device;
>
> if (err < 0) {
> error("%s: error updating services: %s (%d)",
> device->path, strerror(-err), -err);
> goto send_reply;
> }
>
>
> It fails because device->path is not valid.
>
> My patch even though than ugly it worked. I know this is not the best
> for upstream, but at least is something to start with. For some reason
> either user_data or device is invalid when that callback gets.
I guess I finally figure out what could be the source of your
problems, we are not removing the watches when caching the session and
since the context is already freed bt_cancel_discovery doesn't work.
The attached patch should fix this problem, Im also reseting the
internal data of the session by doing sdp_set_notify so if we are not
closing the session it will then reset the callback and data to NULL.
--
Luiz Augusto von Dentz
Computer Engineer
[-- Attachment #2: 0001-core-fix-not-removing-watches-when-caching-sdp-sessi.patch --]
[-- Type: text/x-patch, Size: 1529 bytes --]
From 204247e7ad5dad50ea25188022c725e36cbd6ef5 Mon Sep 17 00:00:00 2001
From: Luiz Augusto von Dentz <luiz.dentz-von@nokia.com>
Date: Thu, 29 Jul 2010 11:28:18 +0300
Subject: [PATCH] core: fix not removing watches when caching sdp session
---
src/glib-helper.c | 19 ++++++++++---------
1 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/src/glib-helper.c b/src/glib-helper.c
index 41f5e3c..e75e270 100644
--- a/src/glib-helper.c
+++ b/src/glib-helper.c
@@ -156,6 +156,12 @@ static void search_context_cleanup(struct search_context *ctxt)
{
context_list = g_slist_remove(context_list, ctxt);
+ if (ctxt->io_id)
+ g_source_remove(ctxt->io_id);
+
+ if (ctxt->session)
+ sdp_close(ctxt->session);
+
if (ctxt->destroy)
ctxt->destroy(ctxt->user_data);
@@ -204,7 +210,10 @@ static void search_completed_cb(uint8_t type, uint16_t status,
} while (scanned < (ssize_t) size && bytesleft > 0);
done:
- cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);
+ if (sdp_set_notify(ctxt->session, NULL, NULL) == 0) {
+ cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session);
+ ctxt->session = NULL;
+ }
if (ctxt->cb)
ctxt->cb(recs, err, ctxt->user_data);
@@ -391,14 +400,6 @@ int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst)
return -ENODATA;
ctxt = match->data;
- if (!ctxt->session)
- return -ENOTCONN;
-
- if (ctxt->io_id)
- g_source_remove(ctxt->io_id);
-
- if (ctxt->session)
- sdp_close(ctxt->session);
search_context_cleanup(ctxt);
return 0;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 6/6] emulator: Add emulator atom in oFono
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
DUN server could create emulator and use GAtServer to talk AT commands
to DUN client side.
---
Makefile.am | 4 +-
include/emulator.h | 41 ++++++++++++++++++
plugins/dun_gw.c | 8 +++
src/emulator.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ofono.h | 3 +
5 files changed, 175 insertions(+), 2 deletions(-)
create mode 100644 include/emulator.h
create mode 100644 src/emulator.c
diff --git a/Makefile.am b/Makefile.am
index 2e08ff2..1ec04f3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -13,7 +13,7 @@ include_HEADERS = include/log.h include/plugin.h include/history.h \
include/cbs.h include/call-volume.h \
include/gprs.h include/gprs-context.h \
include/radio-settings.h include/stk.h \
- include/nettime.h
+ include/nettime.h include/emulator.h
nodist_include_HEADERS = include/version.h
@@ -274,7 +274,7 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) \
src/storage.c src/cbs.c src/watch.c src/call-volume.c \
src/gprs.c src/idmap.h src/idmap.c \
src/radio-settings.c src/stkutil.h src/stkutil.c \
- src/nettime.c
+ src/nettime.c src/emulator.c
src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl
diff --git a/include/emulator.h b/include/emulator.h
new file mode 100644
index 0000000..1033e59
--- /dev/null
+++ b/include/emulator.h
@@ -0,0 +1,41 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __OFONO_EMULATOR_H
+#define __OFONO_EMULATOR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ofono/types.h>
+
+struct ofono_emulator;
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *io);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OFONO_EMULATOR_H */
diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
index 56bd03d..840d22d 100644
--- a/plugins/dun_gw.c
+++ b/plugins/dun_gw.c
@@ -48,6 +48,9 @@ static int modem_watch;
static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
{
+ struct ofono_modem *modem = user_data;
+ struct ofono_emulator *emulator;
+
DBG("");
if (err) {
@@ -55,6 +58,11 @@ static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
goto failed;
}
+ emulator = ofono_emulator_create(modem, OFONO_ATOM_TYPE_EMULATOR_DUN,
+ io);
+ if (!emulator)
+ goto failed;
+
return;
failed:
diff --git a/src/emulator.c b/src/emulator.c
new file mode 100644
index 0000000..6219bb1
--- /dev/null
+++ b/src/emulator.c
@@ -0,0 +1,121 @@
+/*
+ *
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+#include "common.h"
+#include "gatserver.h"
+
+struct ofono_emulator {
+ struct ofono_modem *modem;
+ struct ofono_atom *atom;
+ enum ofono_atom_type type;
+ unsigned int id;
+ GAtServer *server;
+};
+
+static unsigned int ofono_emulator_ids;
+
+static void ofono_emulator_debug(const char *str, void *data)
+{
+ g_print("%s: %s\n", (char *)data, str);
+}
+
+static unsigned int ofono_emulator_next_id()
+{
+ unsigned int i;
+
+ for (i = 1; i < sizeof(ofono_emulator_ids) * 8; i++) {
+ if (ofono_emulator_ids & (0x1 << i))
+ continue;
+
+ ofono_emulator_ids |= (0x1 << i);
+
+ return i;
+ }
+
+ return 0;
+}
+
+static void ofono_emulator_release_id(int id)
+{
+ ofono_emulator_ids &= ~(0x1 << id);
+}
+
+static void emulator_remove(struct ofono_atom *atom)
+{
+ struct ofono_emulator *e = __ofono_atom_get_data(atom);
+
+ DBG("");
+
+ g_at_server_shutdown(e->server);
+ g_at_server_unref(e->server);
+ e->server = NULL;
+
+ ofono_emulator_release_id(e->id);
+ g_free(e);
+ e = NULL;
+}
+
+static void emulator_disconnect(gpointer user_data)
+{
+ struct ofono_emulator *e = user_data;
+
+ __ofono_atom_free(e->atom);
+}
+
+struct ofono_emulator *ofono_emulator_create(struct ofono_modem *modem,
+ enum ofono_atom_type type,
+ GIOChannel *channel)
+{
+ struct ofono_emulator *e;
+
+ DBG("");
+
+ e = g_try_new0(struct ofono_emulator, 1);
+ if (!e)
+ return NULL;
+
+ e->server = g_at_server_new(channel);
+ if (!e->server) {
+ g_free(e);
+ return NULL;
+ }
+
+ g_at_server_set_debug(e->server, ofono_emulator_debug, "Server");
+ g_at_server_set_disconnect_function(e->server, emulator_disconnect, e);
+
+ e->modem = modem;
+ e->type = type;
+ e->id = ofono_emulator_next_id();
+ e->atom = __ofono_modem_add_atom(modem, type, emulator_remove, e);
+
+ return e;
+}
diff --git a/src/ofono.h b/src/ofono.h
index aaa01d9..8982a95 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -117,6 +117,7 @@ enum ofono_atom_type {
OFONO_ATOM_TYPE_RADIO_SETTINGS = 18,
OFONO_ATOM_TYPE_STK = 19,
OFONO_ATOM_TYPE_NETTIME = 20,
+ OFONO_ATOM_TYPE_EMULATOR_DUN = 21,
};
enum ofono_atom_watch_condition {
@@ -289,3 +290,5 @@ void __ofono_nettime_probe_drivers(struct ofono_modem *modem);
void __ofono_nettime_info_received(struct ofono_modem *modem,
struct ofono_network_time *info);
+
+#include <ofono/emulator.h>
--
1.7.0.4
^ permalink raw reply related
* [PATCH 5/6] dun_gw: Add DUN server plugin for oFono
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
DUN server plug-in watches ofono modem status. When the modem comes to
ONLINE state, it registers itself on Bluetooth adapter and want for
incoming DUN connection.
---
Makefile.am | 4 ++
plugins/dun_gw.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 147 insertions(+), 0 deletions(-)
create mode 100644 plugins/dun_gw.c
diff --git a/Makefile.am b/Makefile.am
index e256841..2e08ff2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -242,6 +242,10 @@ builtin_sources += plugins/bluetooth.c plugins/bluetooth.h
builtin_modules += hfp
builtin_sources += plugins/hfp.c plugins/bluetooth.h
+builtin_modules += dun_gw
+builtin_sources += plugins/dun_gw.c plugins/bluetooth.h plugins/btio.c \
+ plugins/btio.h
+
builtin_modules += palmpre
builtin_sources += plugins/palmpre.c
diff --git a/plugins/dun_gw.c b/plugins/dun_gw.c
new file mode 100644
index 0000000..56bd03d
--- /dev/null
+++ b/plugins/dun_gw.c
@@ -0,0 +1,143 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * Copyright (C) 2010 Intel Corporation. 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <ofono.h>
+
+#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono/plugin.h>
+#include <ofono/log.h>
+#include <ofono/modem.h>
+
+#include <ofono/dbus.h>
+
+#include "gdbus.h"
+#include "bluetooth.h"
+
+#ifndef DBUS_TYPE_UNIX_FD
+#define DBUS_TYPE_UNIX_FD -1
+#endif
+
+#define DUN_GW_CHANNEL 1
+
+static struct server *server;
+static int modem_watch;
+
+static void dun_gw_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+ DBG("");
+
+ if (err) {
+ DBG("%s", err->message);
+ goto failed;
+ }
+
+ return;
+
+failed:
+ g_io_channel_shutdown(io, TRUE, NULL);
+ bluetooth_unregister_server(server);
+ server = NULL;
+}
+
+static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
+ void *user_data)
+{
+ const char *property;
+ DBusMessageIter iter, var;
+
+ dbus_message_iter_init(msg, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+
+ if (g_str_equal(property, "Online") == TRUE) {
+ const char *path = dbus_message_get_path(msg);
+ struct ofono_modem *modem;
+ struct ofono_atom *gprs;
+ gboolean online;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ dbus_message_iter_get_basic(&var, &online);
+
+ if (online == FALSE) {
+ bluetooth_unregister_server(server);
+ server = NULL;
+ goto done;
+ }
+
+ /* Create DUN server */
+ modem = ofono_modem_get_modem_by_path(path);
+ gprs = __ofono_modem_find_atom(modem,
+ OFONO_ATOM_TYPE_GPRS);
+ /* Make sure the modem has GPRS atom */
+ if (!gprs)
+ goto done;
+
+ server = bluetooth_register_server(DUN_GW,
+ "Dial-Up Networking", DUN_GW_CHANNEL,
+ dun_gw_connect_cb, modem);
+ }
+
+done:
+ return TRUE;
+}
+
+static int dun_gw_init()
+{
+ DBusConnection *connection = ofono_dbus_get_connection();
+
+ if (DBUS_TYPE_UNIX_FD < 0)
+ return -EBADF;
+
+ modem_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ OFONO_MODEM_INTERFACE,
+ "PropertyChanged",
+ property_changed, NULL, NULL);
+
+ return 0;
+}
+
+static void dun_gw_exit()
+{
+ if (server)
+ bluetooth_unregister_server(server);
+
+ if (modem_watch)
+ g_source_remove(modem_watch);
+}
+
+OFONO_PLUGIN_DEFINE(dun_gw, "Dial-up Networking Profile Plugins", VERSION,
+ OFONO_PLUGIN_PRIORITY_DEFAULT, dun_gw_init, dun_gw_exit)
--
1.7.0.4
^ permalink raw reply related
* [PATCH 4/6] modem: Add method to get modem by path
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
Return modem instance by searching modem path.
---
include/modem.h | 1 +
src/modem.c | 15 +++++++++++++++
2 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/include/modem.h b/include/modem.h
index e1cd049..34c3fbf 100644
--- a/include/modem.h
+++ b/include/modem.h
@@ -36,6 +36,7 @@ void ofono_modem_remove_interface(struct ofono_modem *modem,
const char *interface);
const char *ofono_modem_get_path(struct ofono_modem *modem);
+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path);
void ofono_modem_set_data(struct ofono_modem *modem, void *data);
void *ofono_modem_get_data(struct ofono_modem *modem);
diff --git a/src/modem.c b/src/modem.c
index f89d609..6907a5e 100644
--- a/src/modem.c
+++ b/src/modem.c
@@ -157,6 +157,21 @@ const char *ofono_modem_get_path(struct ofono_modem *modem)
return NULL;
}
+struct ofono_modem *ofono_modem_get_modem_by_path(const char *path)
+{
+ GSList *l;
+ struct ofono_modem *modem = NULL;
+
+ for (l = g_modem_list; l; l = l->next) {
+ modem = l->data;
+
+ if (g_str_equal(modem->path, path))
+ break;
+ }
+
+ return modem;
+}
+
struct ofono_atom *__ofono_modem_add_atom(struct ofono_modem *modem,
enum ofono_atom_type type,
void (*destruct)(struct ofono_atom *),
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/6] bluetooth: Add bluetooth server support for DUN
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
It watches Bluetooth adapter property changes and addes DUN record to
listen DUN client connection request.
---
plugins/bluetooth.c | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/bluetooth.h | 14 ++
2 files changed, 393 insertions(+), 0 deletions(-)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 10cc49d..5890161 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -35,12 +35,71 @@
#include <ofono/dbus.h>
#include "bluetooth.h"
+#include "btio.h"
static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static GSList *server_list = NULL;
static gint ref_count;
+static const gchar *dun_record = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1103\"/> \
+ </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=\"0x1103\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+</record>";
+
+#define TIMEOUT (60*1000) /* Timeout for user response (miliseconds) */
+
+struct client {
+ GIOChannel *io;
+ guint watch;
+};
+
+struct server {
+ guint16 service;
+ gchar *name;
+ guint8 channel;
+ GIOChannel *io;
+ gchar *adapter;
+ guint handle;
+ ConnectFunc connect_cb;
+ gpointer user_data;
+
+ struct client client;
+};
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
{
@@ -370,6 +429,253 @@ static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
return TRUE;
}
+static void disconnect(struct server *server)
+{
+ struct client *client = &server->client;
+
+ if (!client->io)
+ return;
+
+ g_io_channel_unref(client->io);
+ client->io = NULL;
+
+ if (client->watch > 0) {
+ g_source_remove(client->watch);
+ client->watch = 0;
+ }
+
+ return;
+}
+
+static void server_stop(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ if (server->handle) {
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE,
+ server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RemoveRecord");
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ g_dbus_send_message(connection, msg);
+
+ server->handle = 0;
+ }
+
+ if (server->io) {
+ g_io_channel_shutdown(server->io, TRUE, NULL);
+ g_io_channel_unref(server->io);
+ server->io = NULL;
+ }
+
+ g_free(server->adapter);
+ server->adapter = NULL;
+}
+
+static gboolean client_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct server *server = data;
+
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void cancel_authorization(struct server *server)
+{
+ DBusMessage *msg;
+
+ if (!server->adapter)
+ return;
+
+ msg = dbus_message_new_method_call(BLUEZ_SERVICE, server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "CancelAuthorization");
+
+ g_dbus_send_message(connection, msg);
+}
+
+static void auth_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GIOChannel *io = client->io;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ GError *err = NULL;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("RequestAuthorization error: %s, %s",
+ derr.name, derr.message);
+
+ if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
+ cancel_authorization(server);
+
+ dbus_error_free(&derr);
+ goto failed;
+ }
+
+ ofono_info("RequestAuthorization succeeded");
+
+ if (!bt_io_accept(io, server->connect_cb, server->user_data,
+ NULL, &err)) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ g_source_remove(client->watch);
+
+ client->watch = g_io_add_watch(client->io,
+ G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ client_event, server);
+
+ dbus_message_unref(reply);
+
+ return;
+
+failed:
+ dbus_message_unref(reply);
+ disconnect(server);
+}
+
+static gboolean auth_watch(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct server *server = user_data;
+
+ cancel_authorization(server);
+ disconnect(server);
+
+ return FALSE;
+}
+
+static void confirm_event(GIOChannel *io, gpointer user_data)
+{
+ struct server *server = user_data;
+ struct client *client = &server->client;
+ GError *err = NULL;
+ char address[18];
+ const char *addr;
+ guint8 channel;
+ int ret;
+
+ if (client->io) {
+ ofono_error("Rejecting connection since one client already \
+ connected");
+ return;
+ }
+
+ bt_io_get(io, BT_IO_RFCOMM, &err, BT_IO_OPT_DEST, address,
+ BT_IO_OPT_CHANNEL, &channel,
+ BT_IO_OPT_INVALID);
+ if (err) {
+ ofono_error("%s", err->message);
+ g_error_free(err);
+ return;
+ }
+
+ ofono_info("New connection from: %s, channel %u", address, channel);
+
+ addr = address;
+ ret = bluetooth_send_with_reply(server->adapter,
+ BLUEZ_SERVICE_INTERFACE,
+ "RequestAuthorization",
+ auth_cb, server, NULL, TIMEOUT,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_UINT32, &server->handle,
+ DBUS_TYPE_INVALID);
+ if (ret < 0) {
+ ofono_error("Request Bluetooth authorization failed");
+ return;
+ }
+
+ ofono_info("RequestAuthorization(%s, 0x%x)", address, server->handle);
+
+ client->io = g_io_channel_ref(io);
+ client->watch = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ auth_watch, server);
+
+ return;
+}
+
+static void add_record_cb(DBusPendingCall *call, gpointer user_data)
+{
+ struct server *server = user_data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError derr;
+ guint32 handle;
+
+ dbus_error_init(&derr);
+
+ if (dbus_set_error_from_message(&derr, reply)) {
+ ofono_error("Replied with an error: %s, %s",
+ derr.name, derr.message);
+ dbus_error_free(&derr);
+ server_stop(server, NULL);
+ goto done;
+ }
+
+ dbus_message_get_args(reply, NULL, DBUS_TYPE_UINT32, &handle,
+ DBUS_TYPE_INVALID);
+ server->handle = handle;
+
+ ofono_info("Registered: %s, handle: 0x%x", server->name, handle);
+
+done:
+ dbus_message_unref(reply);
+}
+
+static void server_start(gpointer data, gpointer user_data)
+{
+ struct server *server = data;
+ gchar *path = user_data;
+ GError *err = NULL;
+ gchar *xml;
+
+ if (server->handle != 0)
+ return;
+
+ if (server->service != DUN_GW)
+ goto failed;
+
+ server->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event,
+ server, NULL, &err,
+ BT_IO_OPT_CHANNEL, server->channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+ BT_IO_OPT_INVALID);
+ if (!server->io) {
+ ofono_error("Bluetooth %s register failed: %s",
+ server->name, err->message);
+ g_error_free(err);
+ goto failed;
+ }
+
+ server->adapter = g_strdup(path);
+
+ xml = g_markup_printf_escaped(dun_record, server->channel,
+ server->name);
+
+ bluetooth_send_with_reply(path, BLUEZ_SERVICE_INTERFACE, "AddRecord",
+ add_record_cb, server, NULL, -1,
+ DBUS_TYPE_STRING, &xml,
+ DBUS_TYPE_INVALID);
+
+ g_free(xml);
+
+ return;
+
+failed:
+ server_stop(server, NULL);
+}
+
static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
{
const char *path = user_data;
@@ -394,6 +700,9 @@ static void adapter_properties_cb(DBusPendingCall *call, gpointer user_data)
g_hash_table_insert(adapter_address_hash,
g_strdup(path), g_strdup(addr));
+ if (server_list)
+ g_slist_foreach(server_list, server_start, (gpointer)path);
+
for (l = device_list; l; l = l->next) {
const char *device = l->data;
@@ -428,11 +737,26 @@ static gboolean adapter_removed(DBusConnection *connection,
DBusMessage *message, void *user_data)
{
const char *path;
+ GSList *l;
if (dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &path,
DBUS_TYPE_INVALID) == TRUE)
g_hash_table_remove(adapter_address_hash, path);
+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ if (!server->adapter)
+ continue;
+
+ if (!g_str_equal(path, server->adapter))
+ continue;
+
+ /* Don't remove handle if the adapter has been removed */
+ server->handle = 0;
+ server_stop(server, NULL);
+ }
+
return TRUE;
}
@@ -564,6 +888,7 @@ static int bluetooth_ref()
static void bluetooth_unref()
{
gboolean is_zero;
+ GSList *l;
is_zero = g_atomic_int_dec_and_test(&ref_count);
@@ -580,6 +905,20 @@ static void bluetooth_unref()
if (adapter_address_hash)
g_hash_table_destroy(adapter_address_hash);
+
+ if (server_list == NULL)
+ return;
+
+ for (l = server_list; l; l = l->next) {
+ struct server *server = l->data;
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+ }
+
+ g_slist_free(server_list);
+ server_list = NULL;
}
int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
@@ -604,5 +943,45 @@ void bluetooth_unregister_uuid(const char *uuid)
bluetooth_unref();
}
+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data)
+{
+ struct server *server;
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return NULL;
+
+ server = g_try_new0(struct server, 1);
+ if (!server)
+ return NULL;
+
+ server->service = service;
+ server->name = g_strdup(name);
+ server->channel = channel;
+ server->connect_cb = cb;
+ server->user_data = user_data;
+
+ server_list = g_slist_prepend(server_list, server);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+
+ return server;
+}
+
+void bluetooth_unregister_server(struct server *server)
+{
+ server_list = g_slist_remove(server_list, server);
+
+ server_stop(server, NULL);
+ g_free(server->name);
+ g_free(server);
+
+ bluetooth_unref();
+}
+
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
OFONO_PLUGIN_PRIORITY_DEFAULT, NULL, NULL)
diff --git a/plugins/bluetooth.h b/plugins/bluetooth.h
index fb0d841..ab42c99 100644
--- a/plugins/bluetooth.h
+++ b/plugins/bluetooth.h
@@ -2,6 +2,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2010 Gustavo F. Padovan <gustavo@padovan.org>
+ * Copyright (C) 2010 Intel Corporation. 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 version 2 as
@@ -22,12 +23,16 @@
#define BLUEZ_MANAGER_INTERFACE BLUEZ_SERVICE ".Manager"
#define BLUEZ_ADAPTER_INTERFACE BLUEZ_SERVICE ".Adapter"
#define BLUEZ_DEVICE_INTERFACE BLUEZ_SERVICE ".Device"
+#define BLUEZ_SERVICE_INTERFACE BLUEZ_SERVICE ".Service"
#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"
/* Profiles bitfield */
#define HFP_AG 0x01
+/* Service bitfield */
+#define DUN_GW 0x01
+
struct bluetooth_profile {
const char *name;
int (*create)(const char *device, const char *dev_addr,
@@ -36,10 +41,19 @@ struct bluetooth_profile {
void (*set_alias)(const char *device, const char *);
};
+typedef void (*ConnectFunc)(GIOChannel *io, GError *err, gpointer user_data);
+
+struct server;
+
int bluetooth_register_uuid(const char *uuid,
struct bluetooth_profile *profile);
void bluetooth_unregister_uuid(const char *uuid);
+struct server *bluetooth_register_server(guint16 service, char *name,
+ guint8 channel, ConnectFunc cb,
+ gpointer user_data);
+void bluetooth_unregister_server(struct server *server);
+
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 2/6] bluetooth: Add Btio library for DUN
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
Btio library is the low level socket API for BT RFCOMM connection.
---
plugins/btio.c | 479 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
plugins/btio.h | 118 ++++++++++++++
2 files changed, 597 insertions(+), 0 deletions(-)
create mode 100644 plugins/btio.c
create mode 100644 plugins/btio.h
diff --git a/plugins/btio.c b/plugins/btio.c
new file mode 100644
index 0000000..6156027
--- /dev/null
+++ b/plugins/btio.c
@@ -0,0 +1,479 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. 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
+ *
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "btio.h"
+
+#define ERROR_FAILED(gerr, str, err) \
+ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+ str ": %s (%d)", strerror(err), err)
+
+#define DEFAULT_DEFER_TIMEOUT 30
+
+struct set_opts {
+ bdaddr_t src;
+ int defer;
+ int sec_level;
+ uint8_t channel;
+ int master;
+};
+
+struct connect {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct accept {
+ BtIOConnect connect;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+struct server {
+ BtIOConnect connect;
+ BtIOConfirm confirm;
+ gpointer user_data;
+ GDestroyNotify destroy;
+};
+
+static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
+{
+ memcpy(dst, src, sizeof(bdaddr_t));
+}
+
+static void baswap(bdaddr_t *dst, const bdaddr_t *src)
+{
+ register unsigned char *d = (unsigned char *) dst;
+ register const unsigned char *s = (const unsigned char *) src;
+ register int i;
+
+ for (i = 0; i < 6; i++)
+ d[i] = s[5-i];
+}
+
+static int ba2str(const bdaddr_t *ba, char *str)
+{
+ uint8_t b[6];
+
+ baswap((bdaddr_t *) b, ba);
+ return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+ b[0], b[1], b[2], b[3], b[4], b[5]);
+}
+
+static void server_remove(struct server *server)
+{
+ if (server->destroy)
+ server->destroy(server->user_data);
+ g_free(server);
+}
+
+static void accept_remove(struct accept *accept)
+{
+ if (accept->destroy)
+ accept->destroy(accept->user_data);
+ g_free(accept);
+}
+
+static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct accept *accept = user_data;
+ GError *err = NULL;
+
+ /* If the user aborted this accept attempt */
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR))
+ g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
+ "HUP or ERR on socket");
+
+ accept->connect(io, err, accept->user_data);
+
+ g_clear_error(&err);
+
+ return FALSE;
+}
+
+static gboolean server_cb(GIOChannel *io, GIOCondition cond,
+ gpointer user_data)
+{
+ struct server *server = user_data;
+ int srv_sock, cli_sock;
+ GIOChannel *cli_io;
+
+ /* If the user closed the server */
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ srv_sock = g_io_channel_unix_get_fd(io);
+
+ cli_sock = accept(srv_sock, NULL, NULL);
+ if (cli_sock < 0)
+ return TRUE;
+
+ cli_io = g_io_channel_unix_new(cli_sock);
+
+ g_io_channel_set_close_on_unref(cli_io, TRUE);
+ g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL);
+
+ if (server->confirm)
+ server->confirm(cli_io, server->user_data);
+ else
+ server->connect(cli_io, NULL, server->user_data);
+
+ g_io_channel_unref(cli_io);
+
+ return TRUE;
+}
+
+static void server_add(GIOChannel *io, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ struct server *server;
+ GIOCondition cond;
+
+ server = g_new0(struct server, 1);
+ server->connect = connect;
+ server->confirm = confirm;
+ server->user_data = user_data;
+ server->destroy = destroy;
+
+ cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server,
+ (GDestroyNotify) server_remove);
+}
+
+static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy)
+{
+ struct accept *accept;
+ GIOCondition cond;
+
+ accept = g_new0(struct accept, 1);
+ accept->connect = connect;
+ accept->user_data = user_data;
+ accept->destroy = destroy;
+
+ cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+ g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept,
+ (GDestroyNotify) accept_remove);
+}
+
+static int rfcomm_set_lm(int sock, int level)
+{
+ int lm_map[] = {
+ 0,
+ RFCOMM_LM_AUTH,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT,
+ RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE,
+ }, opt = lm_map[level];
+
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
+{
+ struct bt_security sec;
+ int ret;
+
+ if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Valid security level range is %d-%d",
+ BT_SECURITY_LOW, BT_SECURITY_HIGH);
+ return FALSE;
+ }
+
+ memset(&sec, 0, sizeof(sec));
+ sec.level = level;
+
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec,
+ sizeof(sec)) == 0)
+ return TRUE;
+
+ if (errno != ENOPROTOOPT) {
+ ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno);
+ return FALSE;
+ }
+
+ ret = rfcomm_set_lm(sock, level);
+ if (ret < 0) {
+ ERROR_FAILED(err, "setsockopt(LM)", -ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel)
+{
+ struct sockaddr_rc addr;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, src);
+ addr.rc_channel = channel;
+
+ return bind(sock, (struct sockaddr *) &addr, sizeof(addr));
+}
+
+static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err)
+{
+ if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err))
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean parse_set_opts(struct set_opts *opts, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ BtIOOption opt = opt1;
+
+ memset(opts, 0, sizeof(*opts));
+
+ /* Set defaults */
+ opts->defer = DEFAULT_DEFER_TIMEOUT;
+ opts->master = -1;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_CHANNEL:
+ opts->channel = va_arg(args, int);
+ break;
+ case BT_IO_OPT_SEC_LEVEL:
+ opts->sec_level = va_arg(args, int);
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst,
+ socklen_t len, GError **err)
+{
+ socklen_t olen;
+
+ memset(src, 0, len);
+ olen = len;
+ if (getsockname(sock, src, &olen) < 0) {
+ ERROR_FAILED(err, "getsockname", errno);
+ return FALSE;
+ }
+
+ memset(dst, 0, len);
+ olen = len;
+ if (getpeername(sock, dst, &olen) < 0) {
+ ERROR_FAILED(err, "getpeername", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
+ va_list args)
+{
+ BtIOOption opt = opt1;
+ struct sockaddr_rc src, dst;
+
+ if (!get_peers(sock, (struct sockaddr *) &src,
+ (struct sockaddr *) &dst, sizeof(src), err))
+ return FALSE;
+
+ while (opt != BT_IO_OPT_INVALID) {
+ switch (opt) {
+ case BT_IO_OPT_SOURCE:
+ ba2str(&src.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_DEST:
+ ba2str(&dst.rc_bdaddr, va_arg(args, char *));
+ break;
+ case BT_IO_OPT_CHANNEL:
+ *(va_arg(args, uint8_t *)) = src.rc_channel ?
+ src.rc_channel : dst.rc_channel;
+ break;
+ default:
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ return TRUE;
+}
+
+static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, va_list args)
+{
+ int sock = g_io_channel_unix_get_fd(io);
+
+ if (type != BT_IO_RFCOMM) {
+ g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+ "Unknown BtIO type %d", type);
+ return FALSE;
+ }
+
+ return rfcomm_get(sock, err, opt1, args);
+}
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy, GError **err)
+{
+ int sock;
+ char c;
+ struct pollfd pfd;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = sock;
+ pfd.events = POLLOUT;
+
+ if (poll(&pfd, 1, 0) < 0) {
+ ERROR_FAILED(err, "poll", errno);
+ return FALSE;
+ }
+
+ if (!(pfd.revents & POLLOUT)) {
+ int ret;
+ ret = read(sock, &c, 1);
+ }
+
+ accept_add(io, connect, user_data, destroy);
+
+ return TRUE;
+}
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...)
+{
+ va_list args;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = get_valist(io, type, err, opt1, args);
+ va_end(args);
+
+ return ret;
+}
+
+static GIOChannel *create_io(BtIOType type, gboolean server,
+ struct set_opts *opts, GError **err)
+{
+ int sock;
+ GIOChannel *io;
+
+ if (type != BT_IO_RFCOMM)
+ return NULL;
+
+ sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno);
+ return NULL;
+ }
+
+ if (rfcomm_bind(sock, &opts->src,
+ server ? opts->channel : 0) < 0) {
+ ERROR_FAILED(err, "rfcomm_bind", errno);
+ return NULL;
+ }
+
+ if (!rfcomm_set(sock, opts->sec_level, opts->master, err))
+ return NULL;
+
+ io = g_io_channel_unix_new(sock);
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+ g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+
+ return io;
+}
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...)
+{
+ GIOChannel *io;
+ va_list args;
+ struct set_opts opts;
+ int sock;
+ gboolean ret;
+
+ va_start(args, opt1);
+ ret = parse_set_opts(&opts, err, opt1, args);
+ va_end(args);
+
+ if (ret == FALSE)
+ return NULL;
+
+ io = create_io(type, TRUE, &opts, err);
+ if (io == NULL)
+ return NULL;
+
+ sock = g_io_channel_unix_get_fd(io);
+
+ if (confirm)
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+
+ if (listen(sock, 5) < 0) {
+ ERROR_FAILED(err, "listen", errno);
+ g_io_channel_unref(io);
+ return NULL;
+ }
+
+ server_add(io, connect, confirm, user_data, destroy);
+
+ return io;
+}
+
+GQuark bt_io_error_quark(void)
+{
+ return g_quark_from_static_string("bt-io-error-quark");
+}
diff --git a/plugins/btio.h b/plugins/btio.h
new file mode 100644
index 0000000..78d5961
--- /dev/null
+++ b/plugins/btio.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2009 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2009 Nokia Corporation
+ * Copyright (C) 2010 Intel Corporation. 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
+ *
+ */
+
+#include <glib.h>
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+
+#ifndef AF_BLUETOOTH
+#define AF_BLUETOOTH 31
+#define PF_BLUETOOTH AF_BLUETOOTH
+#endif
+
+#define BTPROTO_RFCOMM 3
+#define SOL_RFCOMM 18
+#define SOL_BLUETOOTH 274
+
+struct bt_security {
+ uint8_t level;
+};
+#define BT_SECURITY_SDP 0
+#define BT_SECURITY_LOW 1
+#define BT_SECURITY_MEDIUM 2
+#define BT_SECURITY_HIGH 3
+#define BT_SECURITY 4
+
+#define BT_DEFER_SETUP 7
+
+/* BD Address */
+typedef struct {
+ uint8_t b[6];
+} __attribute__((packed)) bdaddr_t;
+
+#define RFCOMM_LM 0x03
+#define RFCOMM_LM_AUTH 0x0002
+#define RFCOMM_LM_ENCRYPT 0x0004
+#define RFCOMM_LM_TRUSTED 0x0008
+#define RFCOMM_LM_RELIABLE 0x0010
+#define RFCOMM_LM_SECURE 0x0020
+
+#include <sys/socket.h>
+
+/* RFCOMM socket address */
+struct sockaddr_rc {
+ sa_family_t rc_family;
+ bdaddr_t rc_bdaddr;
+ uint8_t rc_channel;
+};
+
+typedef enum {
+ BT_IO_ERROR_DISCONNECTED,
+ BT_IO_ERROR_CONNECT_FAILED,
+ BT_IO_ERROR_FAILED,
+ BT_IO_ERROR_INVALID_ARGS,
+} BtIOError;
+
+#define BT_IO_ERROR bt_io_error_quark()
+
+GQuark bt_io_error_quark(void);
+
+typedef enum {
+ BT_IO_RFCOMM,
+} BtIOType;
+
+typedef enum {
+ BT_IO_OPT_INVALID = 0,
+ BT_IO_OPT_SOURCE,
+ BT_IO_OPT_DEST,
+ BT_IO_OPT_SEC_LEVEL,
+ BT_IO_OPT_CHANNEL,
+} BtIOOption;
+
+typedef enum {
+ BT_IO_SEC_SDP = 0,
+ BT_IO_SEC_LOW,
+ BT_IO_SEC_MEDIUM,
+ BT_IO_SEC_HIGH,
+} BtIOSecLevel;
+
+typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
+
+typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
+
+gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
+ GDestroyNotify destroy, GError **err);
+
+gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
+ BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
+ BtIOConfirm confirm, gpointer user_data,
+ GDestroyNotify destroy, GError **err,
+ BtIOOption opt1, ...);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 1/6] bluetooth: Add reference count for bluetooth utils
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1280387901-8581-1-git-send-email-zhenhua.zhang@intel.com>
Add bluetooth_ref()/bluetooth_unref() to support reference count in
bluetooth utils.
---
plugins/bluetooth.c | 62 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 45 insertions(+), 17 deletions(-)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
index 5a85eaa..10cc49d 100644
--- a/plugins/bluetooth.c
+++ b/plugins/bluetooth.c
@@ -39,6 +39,7 @@
static DBusConnection *connection;
static GHashTable *uuid_hash = NULL;
static GHashTable *adapter_address_hash = NULL;
+static gint ref_count;
void bluetooth_create_path(const char *dev_addr, const char *adapter_addr,
char *buf, int size)
@@ -503,13 +504,10 @@ static guint adapter_added_watch;
static guint adapter_removed_watch;
static guint property_watch;
-int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+static int bluetooth_init()
{
int err;
- if (uuid_hash)
- goto done;
-
connection = ofono_dbus_get_connection();
bluetooth_watch = g_dbus_add_service_watch(connection, BLUEZ_SERVICE,
@@ -542,13 +540,6 @@ int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
adapter_address_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, g_free);
-done:
- g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
-
- bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
- manager_properties_cb, NULL, NULL, -1,
- DBUS_TYPE_INVALID);
-
return 0;
remove:
@@ -556,14 +547,27 @@ remove:
g_dbus_remove_watch(connection, adapter_added_watch);
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);
+
return err;
}
-void bluetooth_unregister_uuid(const char *uuid)
+static int bluetooth_ref()
{
- g_hash_table_remove(uuid_hash, uuid);
+ g_atomic_int_inc(&ref_count);
+
+ if (ref_count > 1)
+ return 0;
+
+ return bluetooth_init();
+}
+
+static void bluetooth_unref()
+{
+ gboolean is_zero;
+
+ is_zero = g_atomic_int_dec_and_test(&ref_count);
- if (g_hash_table_size(uuid_hash))
+ if (is_zero == FALSE)
return;
g_dbus_remove_watch(connection, bluetooth_watch);
@@ -571,9 +575,33 @@ void bluetooth_unregister_uuid(const char *uuid)
g_dbus_remove_watch(connection, adapter_removed_watch);
g_dbus_remove_watch(connection, property_watch);
- g_hash_table_destroy(uuid_hash);
- g_hash_table_destroy(adapter_address_hash);
- uuid_hash = NULL;
+ if (uuid_hash)
+ g_hash_table_destroy(uuid_hash);
+
+ if (adapter_address_hash)
+ g_hash_table_destroy(adapter_address_hash);
+}
+
+int bluetooth_register_uuid(const char *uuid, struct bluetooth_profile *profile)
+{
+ int err = bluetooth_ref();
+
+ if (err != 0)
+ return err;
+
+ g_hash_table_insert(uuid_hash, g_strdup(uuid), profile);
+
+ bluetooth_send_with_reply("/", BLUEZ_MANAGER_INTERFACE, "GetProperties",
+ manager_properties_cb, NULL, NULL, -1,
+ DBUS_TYPE_INVALID);
+ return 0;
+}
+
+void bluetooth_unregister_uuid(const char *uuid)
+{
+ g_hash_table_remove(uuid_hash, uuid);
+
+ bluetooth_unref();
}
OFONO_PLUGIN_DEFINE(bluetooth, "Bluetooth Utils Plugins", VERSION,
--
1.7.0.4
^ permalink raw reply related
* [PATCH 0/6] oFono patches for BT DUN server
From: Zhenhua Zhang @ 2010-07-29 7:18 UTC (permalink / raw)
To: linux-bluetooth
Hi Johan and Luiz,
This series of patches are for BT DUN server support in oFono. Could
you please to review them especially the btio.[ch] changes in patch
2/6.
oFono git: git://git.kernel.org/pub/scm/network/ofono/ofono.git
Thanks.
Zhenhua
^ permalink raw reply
* Re: [PATCH] Bluetooth: host level Support for Atheros AR300x device
From: Marcel Holtmann @ 2010-07-29 6:47 UTC (permalink / raw)
To: suraj; +Cc: linux-bluetooth, Jothikumar.Mothilal
In-Reply-To: <1280380895-5334-1-git-send-email-suraj@atheros.com>
Hi Suraj,
> Implements support for Atheros AR300x Bluetooth chip in
> hciattach application. Supports configuration download
> and power management configure feature.
> ---
> Makefile.tools | 1 +
> tools/hciattach.8 | 6 +
> tools/hciattach.c | 120 +++++++
> tools/hciattach.h | 3 +
> tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 989 insertions(+), 0 deletions(-)
> create mode 100644 tools/hciattach_ar3k.c
>
> diff --git a/Makefile.tools b/Makefile.tools
> index 2dbf925..5dc6a1d 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -23,6 +23,7 @@ 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_ar3k.c \
> tools/hciattach_tialt.c
why do you sort it this way. Leave ti and tialt next to each and just
attach ar3k at the end.
> tools_hciattach_LDADD = lib/libbluetooth.la
>
> diff --git a/tools/hciattach.8 b/tools/hciattach.8
> index 9bd1538..b81e724 100644
> --- a/tools/hciattach.8
> +++ b/tools/hciattach.8
> @@ -66,6 +66,12 @@ specific identifier. Currently supported types are
> .B any
> Unspecified HCI_UART interface, no vendor specific options
> .TP
> +.B ar3kalt
> +Atheros AR300x based serial bluetooth device with power management disabled
> +.TP
> +.B ar3k
> +Atheros AR300x based serial bluetooth device with power management support
> +.TP
We are not doing it this way. Create a proper option of power management
enabled or not.
And it is written Bluetooth.
> .B ericsson
> Ericsson based modules
> .TP
I just hope you tried to sort this alphabetical. Not that the list is
actually alphabetical to begin with.
I actually prefer you just add it after all the other options.
Regards
Marcel
^ permalink raw reply
* [PATCH] Bluetooth: host level Support for Atheros AR300x device
From: suraj @ 2010-07-29 5:21 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
From: Suraj Sumangala <suraj@atheros.com>
Implements support for Atheros AR300x Bluetooth chip in
hciattach application. Supports configuration download
and power management configure feature.
---
Makefile.tools | 1 +
tools/hciattach.8 | 6 +
tools/hciattach.c | 120 +++++++
tools/hciattach.h | 3 +
tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 989 insertions(+), 0 deletions(-)
create mode 100644 tools/hciattach_ar3k.c
diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..5dc6a1d 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,6 +23,7 @@ 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_ar3k.c \
tools/hciattach_tialt.c
tools_hciattach_LDADD = lib/libbluetooth.la
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index 9bd1538..b81e724 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -66,6 +66,12 @@ specific identifier. Currently supported types are
.B any
Unspecified HCI_UART interface, no vendor specific options
.TP
+.B ar3kalt
+Atheros AR300x based serial bluetooth device with power management disabled
+.TP
+.B ar3k
+Atheros AR300x based serial bluetooth device with power management support
+.TP
.B ericsson
Ericsson based modules
.TP
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 81aea7b..3473827 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -654,6 +654,119 @@ 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
+ * with power management dsiabled
+ */
+static int ar3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, SLEEP_DISABLE);
+}
+
+/*
+ * Atheros AR300x specific initialization post callback
+ * with power management enabled
+ */
+static int ar3kpmpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, SLEEP_ENABLE);
+}
+
+#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 ar3kinit(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>
@@ -1073,6 +1186,13 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+ /* ATHEROS AR300x */
+ { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
+ FLOW_CTL, NULL, ar3kinit, ar3kpost },
+
+ { "ar3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
+ FLOW_CTL, NULL, ar3kinit, ar3kpmpost },
+
{ 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
* Re: [PATCH v4 0/5] Enhanced support for extended inquiry response
From: ingas @ 2010-07-28 20:08 UTC (permalink / raw)
To: johan.hedberg; +Cc: ingas, linux-bluetooth, rshaffer, marcel
In-Reply-To: <20100726094444.GB20357@jh-x301>
Hi Johan,
>
> Both the D-Bus interface as well as sdptool trigger the same code paths
> in src/sdpd-service.c. I.e. it doesn't make sense to solve this twice
> when it can be solved once by targetting the common lower layer. We
> already do this for the service class bits with update_svclass_list() in
> sdpd-service.c. The need to update the EIR data is very similar to the
> need to update the service class bits so the existing code is probably a
> good place to take example of.
>
>
My original intent when creating this patch set was no to perturb the code
that is already in place too much. Hence the changes were done only to
D-Bus methods. Sure, I can change the EIR write bot happen deeper down the
pipeline. However, before I invest your and my time in generating and
reviewing more patches , lets agree on the solution first.
In the current implementation, EIR write is keyed off HCI Command
Complete events for a set of commands (in security.c).
- When first registering an OPP service with sdptool, the
update_svcclass_list() (sdpd-service.c) calls manager_update_svc()
(manager.c) which in turn calls adapter_update() (adapter.c). BTW, why
this level of indirection, since manager_update_svc() is called only from
one place in the code and calling adapter_update() is all it does?
Probably some earlier architectural decision I am not aware of
- Anyway, as a result, HCI command to write service class is done, returns
Command Complete event (processed in , calls back into adapter layer
adapter_set_class_complete() which invokes invokes
update_ext_inquiry_response() and (voilà!) EIR is written. So far so good.
- When consequently another OBEX based service like FTP is added using
sdptool, service class of the device does not change, adapter_update()
does nothing, and ultimately EIR is not updated with FTP uuid. This is the
problem that you observed when testing with sdptool. While showing either
only OPP or only FTP might be considered not a big deal, skipping UUID in
EIR for another OBEX-based service like PBAP in EIR might not be so
great, since those services are very different
The current implementation may be extended as following:
Since update_svcclass_list() is being called throughout sdpd-service.c in
all the places where EIR needs to be updated as well, I propose to modify
the corresponding function adapter_set_service_classes() (adapter.c) :
**********************
Before:
/* If we already have the CoD we want or the cache is enabled or an
* existing CoD write is in progress just bail out */
if (adapter->current_cod == adapter->wanted_cod ||
adapter->cache_enable || adapter->pending_cod)
return 0;
***********************
After:
/* If we already have the CoD we want or the cache is enabled or an
* existing CoD write is in progress just bail out */
if (adapter->cache_enable || adapter->pending_cod)
return 0;
/* If we already have the CoD we want, update EIR and return */
if (adapter->current_cod == adapter->wanted_cod ) {
update_ext_inquiry_response(adapter);
return 0;
}
**********************
Will that be acceptable? I tested this modification and its working with
both d-bus methods and sdptool.
Of course, it might be possible to cache the EIR currently written down,
compare the update, and decide whether the EIR needs to be updated. But
this is more involved, not entirely safe, as we might run into coherency
issues.
As a side note, in future it might be a good idea to expose EIR writes to
an application layer providing external API. The intent of EIR is to allow
quick scan of the surroundings to find a particular service that a device
is interested at the moment (and in turn, exposing the services that the
device choses to expose at the moment) without actually going into full
blown connection mode. EIR space is at a premium for sophisticated
devices with multiple services. Not every single service needs to be
exposed in EIR. It would be nice to be able to pick which one to add. For
example, if a device supports both headset and handsfree profiles (as all
of the phones do), it might not be necessary to advertise headset uuid in
EIR since the headsets out there are mostly legacy devices that cannot
perform EIR anyway
Also, as more new services that use uuid128 are
introduced, the EIR buffer pretty quickly if every single one of them is
added without discretion. Just something to throw out there :)
Regards,
Inga
^ permalink raw reply
* Re: [PATCH][RFC] Fix SDP resolving segfault
From: Manuel Naranjo @ 2010-07-28 18:46 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: Johan Hedberg, BlueZ
In-Reply-To: <4C505806.3040508@aircable.net>
Luiz,
Bad news it doesn't work, it keeps doing the same. This is the output
of bluetoothd -n -d:
bluetoothd[3572]: audio/manager.c:handle_uuid() server not enabled for
0000110a-0000-1000-8000-00805f9b34fb (0x110a)
bluetoothd[3572]: audio/manager.c:handle_uuid() Found AV Target
bluetoothd[3572]: audio/control.c:control_init() Registered interface
org.bluez.Control on path /org/bluez/3572/hci0/dev_00_24_91_E4_E9_05
bluetoothd[3572]: audio/manager.c:handle_uuid() Found AV Target
bluetoothd[3572]: src/device.c:btd_device_unref() 0x90f9e08: ref=2
bluetoothd[3572]: src/device.c:btd_device_ref() 0x90f9e08: ref=3
bluetoothd[3572]: src/device.c:search_cb()
/org/bluez/3572/hci0/dev_00_24_91_E4_E9_05: No service update
bluetoothd[3572]: src/device.c:btd_device_unref() 0x90f9e08: ref=2
bluetoothd[3572]: src/adapter.c:session_unref() 0x90b2790: ref=0
bluetoothd[3572]: src/adapter.c:session_remove() Discovery session
0x90b2790 with :1.81 deactivated
bluetoothd[3572]: src/adapter.c:session_remove() Stopping discovery
bluetoothd[3572]: Stopping discovery
bluetoothd[3572]: src/device.c:btd_device_ref() 0x90adfd0: ref=2
bluetoothd[3572]: Discovery session 0x90fe178 with :1.81 activated
bluetoothd[3572]: src/adapter.c:session_ref() 0x90fe178: ref=1
bluetoothd[3572]: src/adapter.c:adapter_remove_connection() Removing
temporary device /org/bluez/3572/hci0/dev_C8_7E_75_DC_1E_86
bluetoothd[3572]: src/device.c:device_remove() Removing device
/org/bluez/3572/hci0/dev_C8_7E_75_DC_1E_86
bluetoothd[3572]: src/device.c:btd_device_unref() 0x90fc080: ref=1
bluetoothd[3572]: src/device.c:btd_device_unref() 0x90fc080: ref=0
bluetoothd[3572]: src/device.c:device_free() 0x90fc080
bluetoothd[3572]: src/adapter.c:adapter_get_device() 00:05:4F:63:5A:E0
bluetoothd[3572]: src/adapter.c:session_unref() 0x90fe178: ref=0
bluetoothd[3572]: src/adapter.c:session_remove() Discovery session
0x90fe178 with :1.81 deactivated
bluetoothd[3572]: src/adapter.c:session_remove() Stopping discovery
bluetoothd[3572]: Stopping discovery
bluetoothd[3572]: Discovery session 0x90b1e00 with :1.81 activated
bluetoothd[3572]: src/adapter.c:session_ref() 0x90b1e00: ref=1
bluetoothd[3572]: <27>Jul 28 14:26:36 bluetoothd[3572]: : error
updating services: Host is down (112)
And this is the call trace during the crash:
+ 4 0x80ac636 (from 0x80a9a28) device_remove_connection():
/home/manuel/bluez/src/device.c:908
+ 5 0x80ac4ca (from 0x80ac753) device_set_connected():
/home/manuel/bluez/src/device.c:875
+ 6 0x80b0d08 (from 0x80ac517) emit_property_changed():
/home/manuel/bluez/src/dbus-common.c:266
+ 7 0x80b0a31 (from 0x80b0da4) append_variant():
/home/manuel/bluez/src/dbus-common.c:195
+ 7 0x805005d (from 0x80b0db6) g_dbus_send_message():
/home/manuel/bluez/gdbus/object.c:615
+ 4 0x80ae60e (from 0x80a9a55) device_get_address():
/home/manuel/bluez/src/device.c:1654
+ 5 0x80aa5a4 (from 0x80ae639) bacpy():
/home/manuel/bluez/./lib/bluetooth/bluetooth.h:132
+ 4 0x808a77f (from 0x80a9a6d) hci_req_queue_remove():
/home/manuel/bluez/src/security.c:169
+ 4 0x80affea (from 0x80a9a78) device_is_authenticating():
/home/manuel/bluez/src/device.c:2339
+ 4 0x80ae749 (from 0x80a9a9a) device_is_temporary():
/home/manuel/bluez/src/device.c:1683
+ 1 0x808a82f (from 0x808cdb4) check_pending_hci_req():
/home/manuel/bluez/src/security.c:186
+ 0 0x8094781 (from 0x2cddab) connect_cb(): /home/manuel/bluez/src/btio.c:138
+ 1 0x8094628 (from 0x80947be) check_nval():
/home/manuel/bluez/src/btio.c:103
+ 1 0x8097b6e (from 0x8094849) bt_io_error_quark():
/home/manuel/bluez/src/btio.c:1296
+ 1 0x8099523 (from 0x80948c1) connect_watch():
/home/manuel/bluez/src/glib-helper.c:283
+ 2 0x80ae1c5 (from 0x809966f) browse_cb():
/home/manuel/bluez/src/device.c:1540
+ 3 0x80adf2f (from 0x80ae312) search_cb():
/home/manuel/bluez/src/device.c:1476
+ 4 0x8089ef6 (from 0x80adf90) error(): /home/manuel/bluez/src/log.c:47
If you go through the code it fails in the line:
static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
{
struct browse_req *req = user_data;
struct btd_device *device = req->device;
if (err < 0) {
error("%s: error updating services: %s (%d)",
device->path, strerror(-err), -err);
goto send_reply;
}
It fails because device->path is not valid.
My patch even though than ugly it worked. I know this is not the best
for upstream, but at least is something to start with. For some reason
either user_data or device is invalid when that callback gets.
Manuel
--
Manuel Francisco Naranjo
Software Department Argentina
Wireless Cables Inc
www.aircable.net
cel: +5493412010019
skype: naranjomanuelfrancisco
^ permalink raw reply
* Re: add dbus api to set class of device?
From: Marcel Holtmann @ 2010-07-28 17:40 UTC (permalink / raw)
To: Tim Renouf; +Cc: linux-bluetooth
In-Reply-To: <20100728165904.GA9840@aplixcorp.com>
Hi Tim,
> > I did mention before that JSR82 is the most stupid Bluetooth API that I
> > have seen so far, didn't I? Personally I wouldn't even bother with JSR82
> > and give up right away. It is really a pointless API.
>
> Unfortunately I have to bother with it as our customers are device
> manufacturers who are willing to pay for MIDP with JSR82 support. :-(
>
> > In BlueZ the services bits of the class of device settings are modified
> > dynamically based on the registered SDP service records. So you don't
> > have to do anything. Just register the right SDP service record with the
> > proper UUID and it will take care of this automatically.
>
> Yes, I saw that in update_adapter_svclass_list. I guess the problem is
> that JSR82 lets an app decide to set the "wrong" bit, and the
> conformance tests test that functionality.
fake the conformance test with just adding and removing the right SDP
records ;)
As I said, JSR82 is the most stupid API I have ever seen. It seems these
guys had no clue about Bluetooth when specifying it. And this is besides
that fact that every application has to implement SDP parsing by itself.
> So if I did a patch along the lines I was suggesting, and submitted it
> here, would it be rejected on the grounds that it is not needed for any
> "sensible" functionality ?
I think you just answered this by yourself. I makes no sense to add such
an API since it has the exact problems that you mentioned earlier. Once
you have two applications this gets messy. And it will not work properly
at all. So for us such an extra API will introduce problems instead of
solving anything.
Regards
Marcel
^ permalink raw reply
* Headset problem
From: Josu Lazkano @ 2010-07-28 17:02 UTC (permalink / raw)
To: linux-bluetooth
Hello, I have a Debian Squeeze laptop, I am using the same OS on other
laptop and I can use a bluetooth headset to speak with PulseAudio.
When I connect
(pairing) the headset I can select the bluetooth device on PulseAudio
and I can use it, but
not with the other laptop.
This is my bt device info:
# hciconfig features
hci0: Type: BR/EDR Bus: USB
BD Address: 00:10:C6:xx:xx:xx ACL MTU: 377:10 SCO MTU: 16:0
UP RUNNING PSCAN ISCAN
RX bytes:5691 acl:77 sco:51 events:125 errors:2
TX bytes:2239 acl:81 sco:0 commands:43 errors:0
I use Gnome bluetooth preference to pair the devices. I don't know
what info put here, can you help with this?
This is the bluetooth device that works:
# hciconfig features
hci0: Type: BR/EDR Bus: USB
BD Address: 00:21:85:xx:xx:xx ACL MTU: 310:10 SCO MTU: 64:8
UP RUNNING PSCAN
RX bytes:312623 acl:19325 sco:0 events:302 errors:0
TX bytes:2074 acl:11 sco:0 commands:41 errors:0
Thanks for all.
--
Josu Lazkano
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox