* Re: [PATCH] Add support for FAX number in phonebook-tracker.c
From: Johan Hedberg @ 2010-08-13 12:19 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1281697117-23072-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Fri, Aug 13, 2010, Radoslaw Jablonski wrote:
> Previously all fax numbers were treated as home phone numbers. Now
> fetching fax field as additional column in tracker query. Data from this
> column is filled as phone number with FAX type set. All pull queries are
> modified that way to suport fax number type.
> ---
> plugins/phonebook-tracker.c | 129 +++++++++++++++++++++++++++++++++---------
> 1 files changed, 101 insertions(+), 28 deletions(-)
Thanks. This patch is now also upstream.
Johan
^ permalink raw reply
* Re: [PATCH] Fix unnecessary checking for empty phones list
From: Johan Hedberg @ 2010-08-13 12:15 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth
In-Reply-To: <1281681311-17074-1-git-send-email-ext-jablonski.radoslaw@nokia.com>
Hi Radek,
On Fri, Aug 13, 2010, Radoslaw Jablonski wrote:
> Removed not needed anymore checking for empty list of phone numbers.
> ---
> plugins/vcard.c | 5 -----
> 1 files changed, 0 insertions(+), 5 deletions(-)
This patch is now upstream. Thanks.
Johan
^ permalink raw reply
* [PATCH] Add support for FAX number in phonebook-tracker.c
From: Radoslaw Jablonski @ 2010-08-13 10:58 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Previously all fax numbers were treated as home phone numbers. Now
fetching fax field as additional column in tracker query. Data from this
column is filled as phone number with FAX type set. All pull queries are
modified that way to suport fax number type.
---
plugins/phonebook-tracker.c | 129 +++++++++++++++++++++++++++++++++---------
1 files changed, 101 insertions(+), 28 deletions(-)
diff --git a/plugins/phonebook-tracker.c b/plugins/phonebook-tracker.c
index 8300fc7..705460d 100644
--- a/plugins/phonebook-tracker.c
+++ b/plugins/phonebook-tracker.c
@@ -43,20 +43,36 @@
#define TRACKER_RESOURCES_INTERFACE "org.freedesktop.Tracker1.Resources"
#define TRACKER_DEFAULT_CONTACT_ME "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#default-contact-me"
-#define CONTACTS_ID_COL 19
+#define CONTACTS_ID_COL 20
+#define PULL_QUERY_COL_AMOUNT 21
+#define COL_HOME_NUMBER 0
+#define COL_WORK_NUMBER 8
+#define COL_FAX_NUMBER 16
+#define COL_DATE 17
+#define COL_SENT 18
+#define COL_ANSWERED 19
#define CONTACTS_QUERY_ALL \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" " \
+ "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
"\"false\" ?c " \
"WHERE { " \
"?c a nco:PersonContact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . \
+ OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "}" \
+ "}" \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -80,13 +96,13 @@
"} GROUP BY ?c"
#define MISSED_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -94,7 +110,16 @@
"nmo:isSent false ; " \
"nmo:isAnswered false ." \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -118,13 +143,13 @@
"} ORDER BY DESC(nmo:receivedDate(?call))"
#define INCOMING_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
@@ -132,7 +157,16 @@
"nmo:isSent false ; " \
"nmo:isAnswered true ." \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -156,20 +190,29 @@
"} ORDER BY DESC(nmo:receivedDate(?call))"
#define OUTGOING_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"?call a nmo:Call ; " \
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -188,17 +231,17 @@
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
"} ORDER BY DESC(nmo:sentDate(?call))"
#define COMBINED_CALLS_QUERY \
- "SELECT nco:phoneNumber(?h) nco:fullname(?c) " \
+ "SELECT ?v nco:fullname(?c) " \
"nco:nameFamily(?c) nco:nameGiven(?c) " \
"nco:nameAdditional(?c) nco:nameHonorificPrefix(?c) " \
"nco:nameHonorificSuffix(?c) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) nmo:receivedDate(?call) " \
+ "nco:postalcode(?p) nco:country(?p) ?f nmo:receivedDate(?call) "\
"nmo:isSent(?call) nmo:isAnswered(?call) ?c " \
"WHERE { " \
"{ " \
@@ -206,7 +249,16 @@
"nmo:to ?c ; " \
"nmo:isSent true . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -218,7 +270,16 @@
"nmo:from ?c ; " \
"nmo:isSent false . " \
"?c a nco:Contact . " \
- "OPTIONAL { ?c nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { ?c nco:hasPhoneNumber ?h . " \
+ "OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "} " \
+ "} " \
"OPTIONAL { ?c nco:hasEmailAddress ?e . } " \
"OPTIONAL { ?c nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -248,17 +309,26 @@
#define CONTACTS_QUERY_FROM_URI \
- "SELECT nco:phoneNumber(?h) nco:fullname(<%s>) " \
+ "SELECT ?v nco:fullname(<%s>) " \
"nco:nameFamily(<%s>) nco:nameGiven(<%s>) " \
"nco:nameAdditional(<%s>) nco:nameHonorificPrefix(<%s>) " \
"nco:nameHonorificSuffix(<%s>) nco:emailAddress(?e) " \
"nco:phoneNumber(?w) nco:pobox(?p) nco:extendedAddress(?p) " \
"nco:streetAddress(?p) nco:locality(?p) nco:region(?p) " \
- "nco:postalcode(?p) nco:country(?p) \"NOTACALL\" \"false\" " \
- "\"false\" <%s> " \
+ "nco:postalcode(?p) nco:country(?p) ?f \"NOTACALL\" \"false\" " \
+ "\"false\" <%s> " \
"WHERE { " \
"<%s> a nco:Contact . " \
- "OPTIONAL { <%s> nco:hasPhoneNumber ?h . } " \
+ "OPTIONAL { <%s> nco:hasPhoneNumber ?h . \
+ OPTIONAL {" \
+ "?h a nco:FaxNumber ; " \
+ "nco:phoneNumber ?f . " \
+ "}" \
+ "OPTIONAL {" \
+ "?h a nco:VoicePhoneNumber ; " \
+ "nco:phoneNumber ?v" \
+ "}" \
+ "}" \
"OPTIONAL { <%s> nco:hasEmailAddress ?e . } " \
"OPTIONAL { <%s> nco:hasPostalAddress ?p . } " \
"OPTIONAL { " \
@@ -660,7 +730,8 @@ static void pull_contacts(char **reply, int num_fields, void *user_data)
}
if (i == num_fields - 4 &&
- !g_str_equal(reply[19], TRACKER_DEFAULT_CONTACT_ME))
+ !g_str_equal(reply[CONTACTS_ID_COL],
+ TRACKER_DEFAULT_CONTACT_ME))
return;
data->index++;
@@ -691,12 +762,14 @@ add_entry:
contact->postal = g_strdup(reply[14]);
contact->country = g_strdup(reply[15]);
- set_call_type(contact, reply[16], reply[17], reply[18]);
+ set_call_type(contact, reply[COL_DATE], reply[COL_SENT],
+ reply[COL_ANSWERED]);
add_numbers:
/* Adding phone numbers to contact struct */
- add_phone_number(contact, reply[0], TEL_TYPE_HOME);
- add_phone_number(contact, reply[8], TEL_TYPE_WORK);
+ add_phone_number(contact, reply[COL_HOME_NUMBER], TEL_TYPE_HOME);
+ add_phone_number(contact, reply[COL_WORK_NUMBER], TEL_TYPE_WORK);
+ add_phone_number(contact, reply[COL_FAX_NUMBER], TEL_TYPE_FAX);
DBG("contact %p", contact);
@@ -868,7 +941,7 @@ int phonebook_pull(const char *name, const struct apparam_field *params,
data->user_data = user_data;
data->cb = cb;
- return query_tracker(query, 20, pull_contacts, data);
+ return query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
}
int phonebook_get_entry(const char *folder, const char *id,
@@ -890,7 +963,7 @@ int phonebook_get_entry(const char *folder, const char *id,
query = g_strdup_printf(CONTACTS_QUERY_FROM_URI, id, id, id, id, id,
id, id, id, id, id, id, id);
- ret = query_tracker(query, 20, pull_contacts, data);
+ ret = query_tracker(query, PULL_QUERY_COL_AMOUNT, pull_contacts, data);
g_free(query);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 3/3] Maemo6 MCE: handle race condition at startup
From: Daniel Örstadius @ 2010-08-13 9:19 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 415 bytes --]
Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the mode change callback. The off_requested member of btd_adapter
is used for the check, so it is set to FALSE when the adapter is
down.
/Daniel
[-- Attachment #2: 0001-Maemo6-MCE-handle-race-condition-at-startup.patch --]
[-- Type: text/x-patch, Size: 2622 bytes --]
From 16455aa43369853f2724d16751a41724df9a4fd5 Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 11:41:37 +0300
Subject: [PATCH] Maemo6 MCE: handle race condition at startup
Since bluetoothd power cycles the adapter at startup, it is possible
that the plugin gets a reply from reading the state of the MCE and
tries to power the adapter before it is down. The patch checks for
that situation and if it occurs postpones powering the adapter to
the mode change callback. The off_requested member of btd_adapter
is used for the check, so it is set to FALSE when the adapter is
down.
---
plugins/maemo6.c | 24 ++++++++++++++++++++++++
src/adapter.c | 1 +
2 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 20e5c00..4a04fa9 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -50,6 +50,7 @@
static guint watch_id;
static DBusConnection *conn = NULL;
static gboolean mce_bt_set = FALSE;
+static gboolean collision = FALSE;
static gboolean mce_signal_callback(DBusConnection *connection,
DBusMessage *message, void *user_data)
@@ -112,6 +113,14 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
+ /* check if the adapter has not completed the initial power
+ cycle, if so delay action to mce_notify_powered */
+
+ collision = adapter_powering_down(adapter);
+
+ if (collision)
+ goto done;
+
if (mce_bt_set)
btd_adapter_switch_online(adapter);
else
@@ -133,6 +142,21 @@ static void adapter_mode_change(struct btd_adapter *adapter, gboolean powered)
if (mce_bt_set == powered)
return;
+ /* check if the plugin got the reply from the mce when the
+ adapter was not yet down during the power cycling when
+ bluetoothd is started */
+ if (collision) {
+ error("maemo6: collision");
+ collision = FALSE;
+
+ if (mce_bt_set)
+ btd_adapter_switch_online(adapter);
+ else
+ btd_adapter_switch_offline(adapter);
+
+ return;
+ }
+
/* set the mce value according to the state of the adapter */
msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ);
diff --git a/src/adapter.c b/src/adapter.c
index ff78539..712ca08 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2502,6 +2502,7 @@ int adapter_stop(struct btd_adapter *adapter)
adapter->state = DISCOVER_TYPE_NONE;
adapter->cache_enable = TRUE;
adapter->pending_cod = 0;
+ adapter->off_requested = FALSE;
adapter_mode_callbacks(adapter, FALSE);
--
1.6.0.4
^ permalink raw reply related
* [PATCH 2/3] Maemo6 MCE: listen to adapter mode changes
From: Daniel Örstadius @ 2010-08-13 9:19 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 437 bytes --]
Registers a callback in btd_adapter to get notified when
the powered state of the adapter is changed. This is needed
to update the state stored in the MCE if the adapter is powered
on or off using for example SetProperty(Powered). The current
setting of the MCE is saved in a variable and if the notification
to the plugin does not match this value the MCE is updated
accordingly using its DBus method for setting radio states.
/Daniel
[-- Attachment #2: 0001-Maemo6-MCE-listen-to-adapter-mode-changes.patch --]
[-- Type: text/x-patch, Size: 3567 bytes --]
From cc89e05c1d406e7d9021030e25e3b32a14bbd28c Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 11:18:32 +0300
Subject: [PATCH] Maemo6 MCE: listen to adapter mode changes
Registers a callback in btd_adapter to get notified when
the powered state of the adapter is changed. This is needed
to update the state stored in the MCE if the adapter is powered
on or off using for example SetProperty(Powered). The current
setting of the MCE is saved in a variable and if the notification
to the plugin does not match this value the MCE is updated
accordingly using its DBus method for setting radio states.
---
plugins/maemo6.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
index 2ed5f12..20e5c00 100644
--- a/plugins/maemo6.c
+++ b/plugins/maemo6.c
@@ -43,11 +43,13 @@
#define MCE_SIGNAL_IF "com.nokia.mce.signal"
#define MCE_REQUEST_PATH "/com/nokia/mce/request"
#define MCE_SIGNAL_PATH "/com/nokia/mce/signal"
+#define MCE_RADIO_STATES_CHANGE_REQ "req_radio_states_change"
#define MCE_RADIO_STATES_GET "get_radio_states"
#define MCE_RADIO_STATES_SIG "radio_states_ind"
static guint watch_id;
static DBusConnection *conn = NULL;
+static gboolean mce_bt_set = FALSE;
static gboolean mce_signal_callback(DBusConnection *connection,
DBusMessage *message, void *user_data)
@@ -66,7 +68,11 @@ static gboolean mce_signal_callback(DBusConnection *connection,
dbus_message_iter_get_basic(&args, &sigvalue);
DBG("got signal with value %u", sigvalue);
- if (sigvalue & MCE_RADIO_STATE_BLUETOOTH)
+ /* set the adapter according to the mce signal
+ and remember the value */
+ mce_bt_set = sigvalue & MCE_RADIO_STATE_BLUETOOTH;
+
+ if (mce_bt_set)
btd_adapter_switch_online(adapter);
else
btd_adapter_switch_offline(adapter);
@@ -102,13 +108,48 @@ static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
goto done;
}
- if (radio_states & MCE_RADIO_STATE_BLUETOOTH)
+ DBG("radio_states: %d", radio_states);
+
+ mce_bt_set = radio_states & MCE_RADIO_STATE_BLUETOOTH;
+
+ if (mce_bt_set)
btd_adapter_switch_online(adapter);
+ else
+ btd_adapter_switch_offline(adapter);
done:
dbus_message_unref(reply);
}
+static void adapter_mode_change(struct btd_adapter *adapter, gboolean powered)
+{
+ DBusMessage *msg;
+ dbus_uint32_t radio_states = 0;
+ dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
+
+ DBG("adapter_mode_change called with %d", (int) powered);
+
+ /* nothing to do if the states match */
+ if (mce_bt_set == powered)
+ return;
+
+ /* set the mce value according to the state of the adapter */
+ msg = dbus_message_new_method_call(MCE_SERVICE, MCE_REQUEST_PATH,
+ MCE_REQUEST_IF, MCE_RADIO_STATES_CHANGE_REQ);
+
+ if (powered)
+ radio_states = MCE_RADIO_STATE_BLUETOOTH;
+
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
+ DBUS_TYPE_UINT32, &radio_mask);
+
+ if (!dbus_connection_send(conn, msg, NULL))
+ error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
+
+ dbus_message_unref(msg);
+}
+
+
static int mce_probe(struct btd_adapter *adapter)
{
DBusMessage *msg;
@@ -132,6 +173,9 @@ static int mce_probe(struct btd_adapter *adapter)
watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
mce_signal_callback, adapter, NULL);
+
+ btd_adapter_register_mode_callback(adapter, adapter_mode_change);
+
return 0;
}
--
1.6.0.4
^ permalink raw reply related
* [PATCH 1/3] Add mode callback to btd_adapter
From: Daniel Örstadius @ 2010-08-13 9:18 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 346 bytes --]
With this patch callback functions can be registered to the
btd_adapter struct. The functions are then called when the powered
state of the adapter changes, with a boolean argument indicating
the new state. The reason for adding the functionality is that the
Maemo6 MCE plugin needs to be notified when the adapter is powered
on or off.
/Daniel
[-- Attachment #2: 0001-Add-mode-callback-to-btd_adapter.patch --]
[-- Type: text/x-patch, Size: 2710 bytes --]
From 489843b65a43773d678bdfe5a3669e3408fdaccc Mon Sep 17 00:00:00 2001
From: Daniel Orstadius <daniel.orstadius@nokia.com>
Date: Fri, 13 Aug 2010 10:30:37 +0300
Subject: [PATCH] Add mode callback to btd_adapter
With this patch callback functions can be registered to the
btd_adapter struct. The functions are then called when the powered
state of the adapter changes, with a boolean argument indicating
the new state. The reason for adding the functionality is that the
Maemo6 MCE plugin needs to be notified when the adapter is powered
on or off.
---
src/adapter.c | 25 +++++++++++++++++++++++++
src/adapter.h | 4 ++++
2 files changed, 29 insertions(+), 0 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index fc1e123..ff78539 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -135,6 +135,8 @@ struct btd_adapter {
gboolean cache_enable;
gint ref;
+
+ GSList *mode_callbacks;
};
static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
@@ -2203,6 +2205,18 @@ static void adapter_disable_cod_cache(struct btd_adapter *adapter)
adapter->pending_cod = adapter->wanted_cod;
}
+static void adapter_mode_callbacks(struct btd_adapter *adapter,
+ gboolean powered)
+{
+ GSList *l;
+
+ for (l = adapter->mode_callbacks; l; l = l->next) {
+ btd_adapter_mode_cb cb = l->data;
+
+ cb(adapter, powered);
+ }
+}
+
static int adapter_up(struct btd_adapter *adapter, const char *mode)
{
char srcaddr[18];
@@ -2283,6 +2297,8 @@ proceed:
ADAPTER_INTERFACE, "Powered",
DBUS_TYPE_BOOLEAN, &powered);
+ adapter_mode_callbacks(adapter, TRUE);
+
adapter_disable_cod_cache(adapter);
return 0;
@@ -2487,6 +2503,8 @@ int adapter_stop(struct btd_adapter *adapter)
adapter->cache_enable = TRUE;
adapter->pending_cod = 0;
+ adapter_mode_callbacks(adapter, FALSE);
+
info("Adapter %s has been disabled", adapter->path);
return 0;
@@ -3422,3 +3440,10 @@ int adapter_ops_setup(void)
return adapter_ops->setup();
}
+
+void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
+ btd_adapter_mode_cb cb)
+{
+ adapter->mode_callbacks =
+ g_slist_append(adapter->mode_callbacks, cb);
+}
diff --git a/src/adapter.h b/src/adapter.h
index a7eca0e..9c7cdf2 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -188,3 +188,7 @@ struct btd_adapter_ops {
int btd_register_adapter_ops(struct btd_adapter_ops *btd_adapter_ops);
void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops);
int adapter_ops_setup(void);
+typedef void (*btd_adapter_mode_cb) (struct btd_adapter *adapter,
+ gboolean powered);
+void btd_adapter_register_mode_callback(struct btd_adapter *adapter,
+ btd_adapter_mode_cb cb);
--
1.6.0.4
^ permalink raw reply related
* Re: [PATCH 2nd version] IrMC sync server support
From: Marcel J.E. Mol @ 2010-08-13 9:05 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimSBnkvoN1x-Ak3Vgk8GNHFjTxoRJmQTV+3ZRys@mail.gmail.com>
On Fri, Aug 13, 2010 at 10:03:35AM +0300, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Fri, Aug 13, 2010 at 12:09 AM, Marcel Mol <marcel@mesa.nl> wrote:
> > A reasonable working IrMC SYNC server (only full phonebook sync support)
> > Support for cal and note by just returning nothing.
> > ---
> > Makefile.am | 3 +
> > plugins/irmc.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> > src/main.c | 10 +-
> > src/obex.h | 3 +-
> > 4 files changed, 521 insertions(+), 2 deletions(-)
> > create mode 100644 plugins/irmc.c
> >
> > diff --git a/Makefile.am b/Makefile.am
> > index 73e2f28..a2873f9 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -55,6 +55,9 @@ builtin_modules += pbap
> > builtin_sources += plugins/pbap.c plugins/phonebook.h \
> > plugins/vcard.h plugins/vcard.c
> >
> > +builtin_modules += irmc
> > +builtin_sources += plugins/irmc.c plugins/phonebook.h
> > +
>
> I guess we don't need phonebook.h, it is already listed in
> builtin-sources before.
Yes, I saw that too, but I think Makefile.am can be optimized even more.
I guess phonebook.h should not be mentioned at the pbabp line either,
but later on at the phonebook.c inclusion.
Also the vcard.h and vcard.h have 'nothing' to do with pbap. The exported
functions from those files are only used by phonebook-tracker...
I intended to file a Makfile.am patch later on....
But I made a few extra changes here so will create a new patch for IrMC
fixing the IrMC makefele.am part (and will nclude the name is NULL check
you mentioned below).
>
> > builtin_modules += syncevolution
> > builtin_sources += plugins/syncevolution.c
> >
> > diff --git a/plugins/irmc.c b/plugins/irmc.c
> > new file mode 100644
> > index 0000000..fa7f91d
> > --- /dev/null
> > +++ b/plugins/irmc.c
> > @@ -0,0 +1,507 @@
> > +/*
> > + *
> > + * OBEX IrMC Sync Server
> > + *
> > + * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> > + *
> > + */
> > +
> > +#ifdef HAVE_CONFIG_H
> > +#include <config.h>
> > +#endif
> > +
> > +#include <stdio.h>
> > +#include <string.h>
> > +#include <errno.h>
> > +#include <glib.h>
> > +#include <stdlib.h>
> > +#include <unistd.h>
> > +#include <arpa/inet.h>
> > +#include <sys/types.h>
> > +#include <sys/stat.h>
> > +#include <fcntl.h>
> > +
> > +#include <openobex/obex.h>
> > +#include <openobex/obex_const.h>
> > +
> > +#include "plugin.h"
> > +#include "log.h"
> > +#include "obex.h"
> > +#include "service.h"
> > +#include "phonebook.h"
> > +#include "mimetype.h"
> > +#include "filesystem.h"
> > +#include "dbus.h"
> > +
> > +#define IRMC_CHANNEL 17
> > +
> > +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> > +<record> \
> > + <attribute id=\"0x0001\"> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0004\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0100\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0003\"/> \
> > + <uint8 value=\"%u\" name=\"channel\"/> \
> > + </sequence> \
> > + <sequence> \
> > + <uuid value=\"0x0008\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0009\"> \
> > + <sequence> \
> > + <sequence> \
> > + <uuid value=\"0x1104\"/> \
> > + <uint16 value=\"0x0100\" name=\"version\"/> \
> > + </sequence> \
> > + </sequence> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0100\"> \
> > + <text value=\"%s\" name=\"name\"/> \
> > + </attribute> \
> > + \
> > + <attribute id=\"0x0301\"> \
> > + <sequence> \
> > + <uint8 value=\"0x01\"/> \
> > + </sequence> \
> > + </attribute> \
> > +</record>"
> > +
> > +
> > +struct aparam_header {
> > + uint8_t tag;
> > + uint8_t len;
> > + uint8_t val[0];
> > +} __attribute__ ((packed));
> > +
> > +#define DID_LEN 18
> > +
> > +struct irmc_session {
> > + struct obex_session *os;
> > + struct apparam_field *params;
> > + uint16_t entries;
> > + GString *buffer;
> > + char sn[DID_LEN];
> > + char did[DID_LEN];
> > + char manu[DID_LEN];
> > + char model[DID_LEN];
> > +};
> > +
> > +#define IRMC_TARGET_SIZE 9
> > +
> > +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> > + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> > +
> > +/*
> > + * FIXME:
> > + * the IrMC specs state the first vcard should be the owner
> > + * vcard. As there is no simple way to collect ownerdetails
> > + * just create an empty vcard (which is allowed according to the
> > + * specs).
> > + */
> > +static const char *owner_vcard =
> > + "BEGIN:VCARD\r\n"
> > + "VERSION:2.1\r\n"
> > + "N:\r\n"
> > + "TEL:\r\n"
> > + "X-IRMX-LUID:0\r\n"
> > + "END:VCARD\r\n";
> > +
> > +static void phonebook_size_result(const char *buffer, size_t bufsize,
> > + int vcards, int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("vcards %d", vcards);
> > +
> > + irmc->params->maxlistcount = vcards;
> > +}
> > +
> > +static void query_result(const char *buffer, size_t bufsize, int vcards,
> > + int missed, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *s, *t;
> > +
> > + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> > +
> > + /* first add a 'owner' vcard */
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new(owner_vcard);
> > + else
> > + irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
> > +
> > + /* loop around buffer and add X-IRMC-LUID attribs */
> > + s = buffer;
> > + while ((t = strstr(s, "UID:")) != NULL) {
> > + /* add upto UID: into buffer */
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + /*
> > + * add UID: line into buffer
> > + * Not sure if UID is still needed if X-IRMC-LUID is there
> > + */
> > + s = t;
> > + t = strstr(s, "\r\n");
> > + t += 2;
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + /* add X-IRMC-LUID with same number as UID */
> > + irmc->buffer = g_string_append_len(irmc->buffer,
> > + "X-IRMC-LUID:", 12);
> > + s += 4; /* point to uid number */
> > + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> > + s = t;
> > + }
> > + /* add remaining bit of buffer */
> > + irmc->buffer = g_string_append(irmc->buffer, s);
> > +
> > + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> > +}
> > +
> > +static void *irmc_connect(struct obex_session *os, int *err)
> > +{
> > + struct irmc_session *irmc;
> > + struct apparam_field *param;
> > +
> > + DBG("");
> > +
> > + manager_register_session(os);
> > +
> > + irmc = g_new0(struct irmc_session, 1);
> > + irmc->os = os;
> > +
> > + /*
> > + * FIXME:
> > + * Ideally get capabilities info here and use that to define
> > + * IrMC DID and SN etc parameters.
> > + * For now lets used hostname and some 'random' value
> > + */
> > + gethostname(irmc->did, DID_LEN);
> > + strncpy(irmc->sn, "12345", DID_LEN);
> > + strncpy(irmc->manu, "obex", DID_LEN);
> > + strncpy(irmc->model, "mymodel", DID_LEN);
> > +
> > + /*
> > + * We need to know the number of contact/cal/nt entries
> > + * somewhere so why not do it now.
> > + */
> > + param = g_new0(struct apparam_field, 1);
> > + param->maxlistcount = 0; /* to count the number of vcards... */
> > + param->filter = 0x200085; /* UID TEL N VERSION */
> > + irmc->params = param;
> > + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> > + irmc);
> > +
> > + if (err)
> > + *err = 0;
> > +
> > + return irmc;
> > +}
> > +
> > +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> > + gboolean *stream, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > + const char *type = obex_get_type(os);
> > + const char *name = obex_get_name(os);
> > + char *path;
> > + int ret;
> > +
> > + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> > +
> > + path = g_strdup(name);
> > + *stream = TRUE;
> > +
> > + ret = obex_get_stream_start(os, path);
> > +
> > + g_free(path);
> > +
> > + return ret;
> > +}
> > +
> > +static void irmc_disconnect(struct obex_session *os, void *user_data)
> > +{
> > + struct irmc_session *irmc = user_data;
> > +
> > + DBG("");
> > +
> > + manager_unregister_session(os);
> > +
> > + if (irmc->params) {
> > + if (irmc->params->searchval)
> > + g_free(irmc->params->searchval);
> > + g_free(irmc->params);
> > + }
> > + if (irmc->buffer) {
> > + string_free(irmc->buffer);
> > + irmc->buffer = NULL;
> > + }
> > +
> > + g_free(irmc);
> > +}
> > +
> > +static int irmc_chkput(struct obex_session *os, void *user_data)
> > +{
> > + DBG("");
> > + /* Reject all PUTs */
> > + return -EBADR;
> > +}
> > +
> > +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> > +{
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + g_string_append_printf(irmc->buffer,
> > + "MANU:%s\r\n"
> > + "MOD:%s\r\n"
> > + "SN:%s\r\n"
> > + "PB-TYPE-TX:VCARD2.1\r\n",
> > + irmc->manu, irmc->model, irmc->sn);
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open_pb(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + GString *mybuf;
> > + int ret;
> > +
> > + if (!g_strcmp0(name, ".vcf")) {
> > + /* how can we tell if the vcard count call already finished? */
> > + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> > + query_result, irmc);
> > + if (ret < 0) {
> > + DBG("phonebook_pull failed...");
> > + goto fail;
> > + }
> > + return irmc;
> > + }
> > +
> > + if (!g_strcmp0(name, "/info.log")) {
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "DID:%s\r\n",
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount, irmc->did);
> > + }
> > + else if (!strncmp(name, "/luid/", 6)) {
> > + name += 6;
> > + if (!g_strcmp0(name, "cc.log")) {
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> > + }
> > + else {
> > + int l = strlen(name);
> > + /* FIXME:
> > + * Reply the same to any *.log so we hopefully force a
> > + * full phonebook dump.
> > + * Is IEL:2 ok?
> > + */
> > + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> > + DBG("changelog request, force whole book");
> > + mybuf = g_string_new("");
> > + g_string_printf(mybuf, "SN:%s\r\n"
> > + "IEL:2\r\n"
> > + "DID:%s\r\n"
> > + "Total-Records:%d\r\n"
> > + "Maximum-Records:%d\r\n"
> > + "*\r\n",
> > + irmc->sn, irmc->did,
> > + irmc->params->maxlistcount,
> > + irmc->params->maxlistcount);
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > + }
> > + }
> > + else {
> > + ret = -EBADR;
> > + goto fail;
> > + }
> > +
> > + if (!irmc->buffer)
> > + irmc->buffer = mybuf;
> > + else {
> > + irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
> > + string_free(mybuf);
> > + }
> > +
> > + return irmc;
> > +
> > +fail:
> > + if (err)
> > + *err = ret;
> > +
> > + return NULL;
> > +}
> > +
> > +static void *irmc_open_cal(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + /* no suport yet. Just return an empty buffer. cal.vcs */
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open_nt(const char *name,
> > + struct irmc_session *irmc, int *err)
> > +{
> > + /* no suport yet. Just return an empty buffer. nt.vnt */
> > + DBG("unsupported, returning empty buffer");
> > + if (!irmc->buffer)
> > + irmc->buffer = g_string_new("");
> > +
> > + return irmc;
> > +}
> > +
> > +static void *irmc_open(const char *name, int oflag, mode_t mode,
> > + void *context, size_t *size, int *err)
> > +{
> > + struct irmc_session *irmc = context;
> > + int ret;
> > + const char *p;
> > +
> > + DBG("name %s context %p", name, context);
> > + if (oflag != O_RDONLY) {
> > + ret = -EPERM;
> > + goto fail;
> > + }
>
> Since Ive seen this many times we better put a check for NULL name
> here otherwise it may crash in the following line.
>
> > + if (strncmp(name, "telecom/", 8) != 0) {
> > + ret = -EBADR;
> > + goto fail;
> > + }
>
>
>
> --
> Luiz Augusto von Dentz
> Computer Engineer
--
======-------- Marcel J.E. Mol MESA Consulting B.V.
=======--------- ph. +31-(0)6-54724868 P.O. Box 112
=======--------- marcel@mesa.nl 2630 AC Nootdorp
__==== www.mesa.nl ---____U_n_i_x______I_n_t_e_r_n_e_t____ The Netherlands ____
They couldn't think of a number, Linux user 1148 -- counter.li.org
so they gave me a name! -- Rupert Hine -- www.ruperthine.com
^ permalink raw reply
* Re: [PATCH] Bluetooth: Process HCI events in a workqueue instead of a tasklet
From: Marcel Holtmann @ 2010-08-13 8:35 UTC (permalink / raw)
To: David Vrabel; +Cc: linux-bluetooth
In-Reply-To: <4C647391.2090607@csr.com>
Hi David,
> >>> so I stuffed this now into bluetooth-testing tree and would like to see
> >>> some extra testing exposure. So far this has only been tested by myself.
> >>>
> >>> If there are no regression then this should make a lot of HCI and L2CAP
> >>> handling a lot simple.
> >> This may result in packets being processed in a different order to that
> >> which they were received in.
> >>
> >> e.g., what happens to an ACL packet processed before the connection
> >> complete event for that connection?
> >
> > good point. So we would either a) need to disable the RX tasklet when we
> > receive an event and schedule it for processing or b) process the ACL
> > data also in a workqueue.
>
> I've thought some more about this and I'm not sure disabling the tasklet
> is sufficient to prevent packets being reordered. Consider a transport
> that submits (in the same interrupt handler call) an ACL packet and an
> HCI event. The tasklet will be scheduled and then disabled until the
> event is processed in the workqueue.
>
> On the other hand, USB transports do not ensure any ordering between HCI
> event and ACL packets because they're received on different USB
> endpoints which could be processed in any order.
so lets see here. We expect that hci_recv_frame receives the events and
data packets in proper order. If it happens that the USB controller does
a different order, then it is the USB controllers problem. We just can't
fix that in the Bluetooth core since we don't know the expected order.
So we must assume whatever gets received via hci_recv_frame is the
correct order.
switch (bt_cb(skb)->pkt_type) {
case HCI_EVENT_PKT:
/* Queue frame for event processing */
skb_queue_tail(&hdev->evt_q, skb);
queue_work(hdev->workqueue, &hdev->evt_work);
break;
default:
/* Queue frame for rx task */
skb_queue_tail(&hdev->rx_q, skb);
tasklet_schedule(&hdev->rx_task);
break;
}
If we now disable the rx_task before scheduling the evt_work, then the
rx_task gets scheduled, but only run after we enable rx_task again. And
we enable the rx_task after hci_event_packet. So after we have created
any structure to handle the ACL and SCO data packets correctly.
I am not seeing your concern. At least not in the Bluetooth core. There
might be a few driver issues when the controller doesn't send us things
in order, but that is really a controller or driver issue at that point.
Coming to think about this, we might even go one step further here and
only enable the rx_task when we have an ACL link. That way if the
controller sends us an ACL packet before the Connection Complete event
we just queue it up. That would potentially solve issues that we have
seen with Broadcom controllers where the first ACL packet arrives too
early and BlueZ is just too fast.
We could even go one step further with this and only enable the RX task
when we have switched on encryption (for 2.1 with SSP). This might fix
some issues with the stupid controllers sending ACL packets before
notifying us that the link has switched on encryption.
Anyway, I am really open for suggestions here. I just think that moving
all RX and TX processing into a workqueue might be a bit overkill. And
keep processing events in a tasklet will create code complexity in the
future when adding AMP support.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH 2nd version] IrMC sync server support
From: Luiz Augusto von Dentz @ 2010-08-13 7:03 UTC (permalink / raw)
To: Marcel Mol; +Cc: linux-bluetooth
In-Reply-To: <201008122116.o7CLGo4p017361@joshua.mesa.nl>
Hi Marcel,
On Fri, Aug 13, 2010 at 12:09 AM, Marcel Mol <marcel@mesa.nl> wrote:
> A reasonable working IrMC SYNC server (only full phonebook sync support)
> Support for cal and note by just returning nothing.
> ---
> Makefile.am | 3 +
> plugins/irmc.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> src/main.c | 10 +-
> src/obex.h | 3 +-
> 4 files changed, 521 insertions(+), 2 deletions(-)
> create mode 100644 plugins/irmc.c
>
> diff --git a/Makefile.am b/Makefile.am
> index 73e2f28..a2873f9 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -55,6 +55,9 @@ builtin_modules += pbap
> builtin_sources += plugins/pbap.c plugins/phonebook.h \
> plugins/vcard.h plugins/vcard.c
>
> +builtin_modules += irmc
> +builtin_sources += plugins/irmc.c plugins/phonebook.h
> +
I guess we don't need phonebook.h, it is already listed in
builtin-sources before.
> builtin_modules += syncevolution
> builtin_sources += plugins/syncevolution.c
>
> diff --git a/plugins/irmc.c b/plugins/irmc.c
> new file mode 100644
> index 0000000..fa7f91d
> --- /dev/null
> +++ b/plugins/irmc.c
> @@ -0,0 +1,507 @@
> +/*
> + *
> + * OBEX IrMC Sync Server
> + *
> + * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <errno.h>
> +#include <glib.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <arpa/inet.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include <openobex/obex.h>
> +#include <openobex/obex_const.h>
> +
> +#include "plugin.h"
> +#include "log.h"
> +#include "obex.h"
> +#include "service.h"
> +#include "phonebook.h"
> +#include "mimetype.h"
> +#include "filesystem.h"
> +#include "dbus.h"
> +
> +#define IRMC_CHANNEL 17
> +
> +#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
> +<record> \
> + <attribute id=\"0x0001\"> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0004\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x0100\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0003\"/> \
> + <uint8 value=\"%u\" name=\"channel\"/> \
> + </sequence> \
> + <sequence> \
> + <uuid value=\"0x0008\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0009\"> \
> + <sequence> \
> + <sequence> \
> + <uuid value=\"0x1104\"/> \
> + <uint16 value=\"0x0100\" name=\"version\"/> \
> + </sequence> \
> + </sequence> \
> + </attribute> \
> + \
> + <attribute id=\"0x0100\"> \
> + <text value=\"%s\" name=\"name\"/> \
> + </attribute> \
> + \
> + <attribute id=\"0x0301\"> \
> + <sequence> \
> + <uint8 value=\"0x01\"/> \
> + </sequence> \
> + </attribute> \
> +</record>"
> +
> +
> +struct aparam_header {
> + uint8_t tag;
> + uint8_t len;
> + uint8_t val[0];
> +} __attribute__ ((packed));
> +
> +#define DID_LEN 18
> +
> +struct irmc_session {
> + struct obex_session *os;
> + struct apparam_field *params;
> + uint16_t entries;
> + GString *buffer;
> + char sn[DID_LEN];
> + char did[DID_LEN];
> + char manu[DID_LEN];
> + char model[DID_LEN];
> +};
> +
> +#define IRMC_TARGET_SIZE 9
> +
> +static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
> + 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
> +
> +/*
> + * FIXME:
> + * the IrMC specs state the first vcard should be the owner
> + * vcard. As there is no simple way to collect ownerdetails
> + * just create an empty vcard (which is allowed according to the
> + * specs).
> + */
> +static const char *owner_vcard =
> + "BEGIN:VCARD\r\n"
> + "VERSION:2.1\r\n"
> + "N:\r\n"
> + "TEL:\r\n"
> + "X-IRMX-LUID:0\r\n"
> + "END:VCARD\r\n";
> +
> +static void phonebook_size_result(const char *buffer, size_t bufsize,
> + int vcards, int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("vcards %d", vcards);
> +
> + irmc->params->maxlistcount = vcards;
> +}
> +
> +static void query_result(const char *buffer, size_t bufsize, int vcards,
> + int missed, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *s, *t;
> +
> + DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
> +
> + /* first add a 'owner' vcard */
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new(owner_vcard);
> + else
> + irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
> +
> + /* loop around buffer and add X-IRMC-LUID attribs */
> + s = buffer;
> + while ((t = strstr(s, "UID:")) != NULL) {
> + /* add upto UID: into buffer */
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + /*
> + * add UID: line into buffer
> + * Not sure if UID is still needed if X-IRMC-LUID is there
> + */
> + s = t;
> + t = strstr(s, "\r\n");
> + t += 2;
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + /* add X-IRMC-LUID with same number as UID */
> + irmc->buffer = g_string_append_len(irmc->buffer,
> + "X-IRMC-LUID:", 12);
> + s += 4; /* point to uid number */
> + irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
> + s = t;
> + }
> + /* add remaining bit of buffer */
> + irmc->buffer = g_string_append(irmc->buffer, s);
> +
> + obex_object_set_io_flags(irmc, G_IO_IN, 0);
> +}
> +
> +static void *irmc_connect(struct obex_session *os, int *err)
> +{
> + struct irmc_session *irmc;
> + struct apparam_field *param;
> +
> + DBG("");
> +
> + manager_register_session(os);
> +
> + irmc = g_new0(struct irmc_session, 1);
> + irmc->os = os;
> +
> + /*
> + * FIXME:
> + * Ideally get capabilities info here and use that to define
> + * IrMC DID and SN etc parameters.
> + * For now lets used hostname and some 'random' value
> + */
> + gethostname(irmc->did, DID_LEN);
> + strncpy(irmc->sn, "12345", DID_LEN);
> + strncpy(irmc->manu, "obex", DID_LEN);
> + strncpy(irmc->model, "mymodel", DID_LEN);
> +
> + /*
> + * We need to know the number of contact/cal/nt entries
> + * somewhere so why not do it now.
> + */
> + param = g_new0(struct apparam_field, 1);
> + param->maxlistcount = 0; /* to count the number of vcards... */
> + param->filter = 0x200085; /* UID TEL N VERSION */
> + irmc->params = param;
> + phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
> + irmc);
> +
> + if (err)
> + *err = 0;
> +
> + return irmc;
> +}
> +
> +static int irmc_get(struct obex_session *os, obex_object_t *obj,
> + gboolean *stream, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> + const char *type = obex_get_type(os);
> + const char *name = obex_get_name(os);
> + char *path;
> + int ret;
> +
> + DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
> +
> + path = g_strdup(name);
> + *stream = TRUE;
> +
> + ret = obex_get_stream_start(os, path);
> +
> + g_free(path);
> +
> + return ret;
> +}
> +
> +static void irmc_disconnect(struct obex_session *os, void *user_data)
> +{
> + struct irmc_session *irmc = user_data;
> +
> + DBG("");
> +
> + manager_unregister_session(os);
> +
> + if (irmc->params) {
> + if (irmc->params->searchval)
> + g_free(irmc->params->searchval);
> + g_free(irmc->params);
> + }
> + if (irmc->buffer) {
> + string_free(irmc->buffer);
> + irmc->buffer = NULL;
> + }
> +
> + g_free(irmc);
> +}
> +
> +static int irmc_chkput(struct obex_session *os, void *user_data)
> +{
> + DBG("");
> + /* Reject all PUTs */
> + return -EBADR;
> +}
> +
> +static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
> +{
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + g_string_append_printf(irmc->buffer,
> + "MANU:%s\r\n"
> + "MOD:%s\r\n"
> + "SN:%s\r\n"
> + "PB-TYPE-TX:VCARD2.1\r\n",
> + irmc->manu, irmc->model, irmc->sn);
> +
> + return irmc;
> +}
> +
> +static void *irmc_open_pb(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + GString *mybuf;
> + int ret;
> +
> + if (!g_strcmp0(name, ".vcf")) {
> + /* how can we tell if the vcard count call already finished? */
> + ret = phonebook_pull("telecom/pb.vcf", irmc->params,
> + query_result, irmc);
> + if (ret < 0) {
> + DBG("phonebook_pull failed...");
> + goto fail;
> + }
> + return irmc;
> + }
> +
> + if (!g_strcmp0(name, "/info.log")) {
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "DID:%s\r\n",
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount, irmc->did);
> + }
> + else if (!strncmp(name, "/luid/", 6)) {
> + name += 6;
> + if (!g_strcmp0(name, "cc.log")) {
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
> + }
> + else {
> + int l = strlen(name);
> + /* FIXME:
> + * Reply the same to any *.log so we hopefully force a
> + * full phonebook dump.
> + * Is IEL:2 ok?
> + */
> + if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
> + DBG("changelog request, force whole book");
> + mybuf = g_string_new("");
> + g_string_printf(mybuf, "SN:%s\r\n"
> + "IEL:2\r\n"
> + "DID:%s\r\n"
> + "Total-Records:%d\r\n"
> + "Maximum-Records:%d\r\n"
> + "*\r\n",
> + irmc->sn, irmc->did,
> + irmc->params->maxlistcount,
> + irmc->params->maxlistcount);
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> + }
> + }
> + else {
> + ret = -EBADR;
> + goto fail;
> + }
> +
> + if (!irmc->buffer)
> + irmc->buffer = mybuf;
> + else {
> + irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
> + string_free(mybuf);
> + }
> +
> + return irmc;
> +
> +fail:
> + if (err)
> + *err = ret;
> +
> + return NULL;
> +}
> +
> +static void *irmc_open_cal(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + /* no suport yet. Just return an empty buffer. cal.vcs */
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + return irmc;
> +}
> +
> +static void *irmc_open_nt(const char *name,
> + struct irmc_session *irmc, int *err)
> +{
> + /* no suport yet. Just return an empty buffer. nt.vnt */
> + DBG("unsupported, returning empty buffer");
> + if (!irmc->buffer)
> + irmc->buffer = g_string_new("");
> +
> + return irmc;
> +}
> +
> +static void *irmc_open(const char *name, int oflag, mode_t mode,
> + void *context, size_t *size, int *err)
> +{
> + struct irmc_session *irmc = context;
> + int ret;
> + const char *p;
> +
> + DBG("name %s context %p", name, context);
> + if (oflag != O_RDONLY) {
> + ret = -EPERM;
> + goto fail;
> + }
Since Ive seen this many times we better put a check for NULL name
here otherwise it may crash in the following line.
> + if (strncmp(name, "telecom/", 8) != 0) {
> + ret = -EBADR;
> + goto fail;
> + }
--
Luiz Augusto von Dentz
Computer Engineer
^ permalink raw reply
* [PATCH v2 2/2] Bluetooth: host level Support for Atheros AR300x device
From: Suraj Sumangala @ 2010-08-13 6:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
In-Reply-To: <1281681408-27376-1-git-send-email-suraj@atheros.com>
Implements support for Atheros AR300x Bluetooth chip in
hciattach application. Supports configuration download
and power management configure feature.
---
Makefile.tools | 7 +-
tools/hciattach.8 | 3 +
tools/hciattach.c | 105 ++++++
tools/hciattach.h | 3 +
tools/hciattach_ar3k.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 974 insertions(+), 3 deletions(-)
create mode 100644 tools/hciattach_ar3k.c
diff --git a/Makefile.tools b/Makefile.tools
index 2dbf925..e568bd7 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -21,9 +21,10 @@ tools_rfcomm_LDADD = lib/libbluetooth.la
tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
- tools/hciattach_st.c \
- tools/hciattach_ti.c \
- tools/hciattach_tialt.c
+ tools/hciattach_st.c \
+ tools/hciattach_ti.c \
+ tools/hciattach_tialt.c \
+ tools/hciattach_ar3k.c
tools_hciattach_LDADD = lib/libbluetooth.la
tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f443dff..e0e2730 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -86,6 +86,9 @@ Silicon Wave kits
.TP
.B bcsp
Serial adapters using CSR chips with BCSP serial protocol
+.TP
+.B ath3k
+Atheros AR300x based serial Bluetooth device
.RE
Supported IDs are (manufacturer id, product id)
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 8616899..6cc92c1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -657,6 +657,109 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
return 0;
}
+#define SLEEP_ENABLE 1
+#define SLEEP_DISABLE 0
+
+/*
+ * Atheros AR300x specific initialization post callback
+ */
+static int ath3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, u->pm);
+}
+
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+#define HCI_CHG_BAUD_CMD_OCF 0x0C
+
+#define WRITE_BDADDR_CMD_LEN 14
+#define WRITE_BAUD_CMD_LEN 6
+#define MAX_CMD_LEN WRITE_BDADDR_CMD_LEN
+
+/*
+ * Atheros AR300x specific initialization and configureation file
+ * download
+ */
+static int ath3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ int r;
+ int baud;
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[MAX_CMD_LEN], rsp[HCI_MAX_EVENT_SIZE];
+ unsigned char *ptr = cmd + 1;
+ hci_command_hdr *ch = (void *)ptr;
+
+ cmd[0] = HCI_COMMAND_PKT;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -ETIMEDOUT;
+ }
+
+ /* Write BDADDR */
+ if (u->bdaddr) {
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *)(ptr + 4));
+
+ if (write(fd, cmd, WRITE_BDADDR_CMD_LEN) !=
+ WRITE_BDADDR_CMD_LEN) {
+ perror("Failed to write BD_ADDR command\n");
+ return -ETIMEDOUT;
+ }
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0) {
+ perror("Failed to set BD_ADDR\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /* Send HCI Reset */
+ cmd[1] = 0x03;
+ cmd[2] = 0x0C;
+ cmd[3] = 0x00;
+
+ r = write(fd, cmd, 4);
+ if (r != 4)
+ return -ETIMEDOUT;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -ETIMEDOUT;
+
+ /* set controller baud rate to user specified value */
+ ptr = cmd + 1;
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_CHG_BAUD_CMD_OCF));
+ ch->plen = 2;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ baud = u->speed/100;
+ ptr[0] = (char)baud;
+ ptr[1] = (char)(baud >> 8);
+
+ if (write(fd, cmd, WRITE_BAUD_CMD_LEN) != WRITE_BAUD_CMD_LEN) {
+ perror("Failed to write change baud rate command");
+ return -ETIMEDOUT;
+ }
+
+ nanosleep(&tm, NULL);
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
/*
* Silicon Wave specific initialization
* Thomas Moser <thomas.moser@tmoser.ch>
@@ -1104,6 +1207,8 @@ struct uart_t uart[] = {
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800,
FLOW_CTL, DISABLE_PM, NULL, bcm2035 },
+ { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, ath3kinit, ath3kpost },
{ NULL, 0 }
};
diff --git a/tools/hciattach.h b/tools/hciattach.h
index c0b80a1..ca31731 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -38,6 +38,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH3K 5
#define HCI_UART_RAW_DEVICE 0
@@ -49,3 +50,5 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath_configure_sleep(int fd, int sleep_stat);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100644
index 0000000..ffd143f
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,859 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define FW_PATH "/lib/firmware/ar3k/"
+
+struct ps_cfg_entry {
+ uint32_t id;
+ uint32_t len;
+ uint8_t *data;
+};
+
+struct ps_entry_type {
+ unsigned char type;
+ unsigned char array;
+};
+
+#define MAX_TAGS 50
+#define PS_HDR_LEN 4
+#define HCI_VENDOR_CMD_OGF 0x3F
+#define HCI_PS_CMD_OCF 0x0B
+
+struct ps_cfg_entry ps_list[MAX_TAGS];
+
+static void load_hci_ps_hdr(uint8_t *cmd, uint8_t ps_op, int len, int index)
+{
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = len + PS_HDR_LEN;
+ cmd += HCI_COMMAND_HDR_SIZE;
+
+ cmd[0] = ps_op;
+ cmd[1] = index;
+ cmd[2] = index >> 8;
+ cmd[3] = len;
+}
+
+#define PS_EVENT_LEN 100
+
+/*
+ * Send HCI command and wait for command complete event.
+ * The event buffer has to be freed by the caller.
+ */
+static int send_hci_cmd_sync(int dev, uint8_t *cmd, int len, uint8_t **event)
+{
+ int err;
+ uint8_t *hci_event;
+ uint8_t pkt_type = HCI_COMMAND_PKT;
+
+ if (len == 0)
+ return len;
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -EILSEQ;
+ if (write(dev, (unsigned char *)cmd, len) != len)
+ return -EILSEQ;
+
+ hci_event = (uint8_t *)malloc(PS_EVENT_LEN);
+ if (!hci_event)
+ return -ENOMEM;
+
+ err = read_hci_event(dev, (unsigned char *)hci_event, PS_EVENT_LEN);
+ if (err > 0) {
+ *event = hci_event;
+ } else {
+ free(hci_event);
+ return -EILSEQ;
+ }
+
+ return len;
+}
+
+#define HCI_EV_SUCCESS 0x00
+
+static int read_ps_event(uint8_t *event, uint16_t ocf)
+{
+ hci_event_hdr *eh;
+ uint16_t opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF, ocf));
+
+ event++;
+
+ eh = (void *)event;
+ event += HCI_EVENT_HDR_SIZE;
+
+ if (eh->evt == EVT_CMD_COMPLETE) {
+ evt_cmd_complete *cc = (void *)event;
+
+ event += EVT_CMD_COMPLETE_SIZE;
+
+ if (cc->opcode == opcode && event[0] == HCI_EV_SUCCESS)
+ return 0;
+ else
+ return -EILSEQ;
+ }
+
+ return -EILSEQ;
+}
+
+static int write_cmd(int fd, uint8_t *buffer, int len)
+{
+ uint8_t *event;
+ int err;
+
+ err = send_hci_cmd_sync(fd, buffer, len, &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define PS_WRITE 1
+#define PS_RESET 2
+#define WRITE_PATCH 8
+#define ENABLE_PATCH 11
+
+#define HCI_PS_CMD_HDR_LEN 7
+
+#define PS_RESET_PARAM_LEN 6
+#define HCI_MAX_CMD_SIZE 260
+#define PS_RESET_CMD_LEN (HCI_PS_CMD_HDR_LEN + PS_RESET_PARAM_LEN)
+
+#define PS_ID_MASK 0xFF
+
+/* Sends PS commands using vendor specficic HCI commands */
+static int write_ps_cmd(int fd, uint8_t opcode, uint32_t ps_param)
+{
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ int i;
+
+ switch (opcode) {
+ case ENABLE_PATCH:
+ load_hci_ps_hdr(cmd, opcode, 0, 0x00);
+
+ if (write_cmd(fd, cmd, HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_RESET:
+ load_hci_ps_hdr(cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
+
+ cmd[7] = 0x00;
+ cmd[PS_RESET_CMD_LEN - 2] = ps_param & PS_ID_MASK;
+ cmd[PS_RESET_CMD_LEN - 1] = (ps_param >> 8) & PS_ID_MASK;
+
+ if (write_cmd(fd, cmd, PS_RESET_CMD_LEN) < 0)
+ return -EILSEQ;
+ break;
+
+ case PS_WRITE:
+ for (i = 0; i < ps_param; i++) {
+ load_hci_ps_hdr(cmd, opcode, ps_list[i].len,
+ ps_list[i].id);
+
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], ps_list[i].data,
+ ps_list[i].len);
+
+ if (write_cmd(fd, cmd, ps_list[i].len +
+ HCI_PS_CMD_HDR_LEN) < 0)
+ return -EILSEQ;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+#define __is_delim(ch) ((ch) == ':')
+#define MAX_PREAMBLE_LEN 4
+
+/* Parse PS entry preamble of format [X:X] for main type and subtype */
+static int get_ps_type(char *ptr, int index, char *type, char *sub_type)
+{
+ int i;
+ int delim = FALSE;
+
+ if (index > MAX_PREAMBLE_LEN)
+ return -EILSEQ;
+
+ for (i = 1; i < index; i++) {
+ if (__is_delim(ptr[i])) {
+ delim = TRUE;
+ continue;
+ }
+
+ if (isalpha(ptr[i])) {
+ if (delim == FALSE)
+ (*type) = toupper(ptr[i]);
+ else
+ (*sub_type) = toupper(ptr[i]);
+ }
+ }
+
+ return 0;
+}
+
+#define ARRAY 'A'
+#define STRING 'S'
+#define DECIMAL 'D'
+#define BINARY 'B'
+
+#define PS_HEX 0
+#define PS_DEC 1
+
+static int get_input_format(char *buf, struct ps_entry_type *format)
+{
+ char *ptr = NULL;
+ char type = '\0';
+ char sub_type = '\0';
+
+ format->type = PS_HEX;
+ format->array = TRUE;
+
+ if (strstr(buf, "[") != buf)
+ return 0;
+
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return -EILSEQ;
+
+ if (get_ps_type(buf, ptr - buf, &type, &sub_type) < 0)
+ return -EILSEQ;
+
+ /* Check is data type is of array */
+ if (type == ARRAY || sub_type == ARRAY)
+ format->array = TRUE;
+
+ if (type == STRING || sub_type == STRING)
+ format->array = FALSE;
+
+ if (type == DECIMAL || type == BINARY)
+ format->type = PS_DEC;
+ else
+ format->type = PS_HEX;
+
+ return 0;
+}
+
+#define UNDEFINED 0xFFFF
+
+static unsigned int read_data_in_section(char *buf, struct ps_entry_type type)
+{
+ char *ptr = buf;
+
+ if (!buf)
+ return UNDEFINED;
+
+ if (buf == strstr(buf, "[")) {
+ ptr = strstr(buf, "]");
+ if (!ptr)
+ return UNDEFINED;
+
+ ptr++;
+ }
+
+ if (type.type == PS_HEX && type.array != TRUE)
+ return strtol(ptr, NULL, 16);
+
+ return UNDEFINED;
+}
+
+struct tag_info {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+static inline int update_char_count(const char *buf)
+{
+ char *end_ptr;
+
+ if (strstr(buf, "[") == buf) {
+ end_ptr = strstr(buf, "]");
+ if (!end_ptr)
+ return 0;
+ else
+ return (end_ptr - buf) + 1;
+ }
+
+ return 0;
+}
+
+/* Read PS entries as string, convert and add to Hex array */
+static void update_tag_data(struct ps_cfg_entry *tag,
+ struct tag_info *info, const char *ptr)
+{
+ char buf[3];
+
+ buf[2] = '\0';
+
+ strncpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+
+ strncpy(buf, &ptr[info->char_cnt], 2);
+ tag->data[info->byte_count] = strtol(buf, NULL, 16);
+ info->char_cnt += 3;
+ info->byte_count++;
+}
+
+#define PS_UNDEF 0
+#define PS_ID 1
+#define PS_LEN 2
+#define PS_DATA 3
+
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+#define ENTRY_PER_LINE 16
+
+#define __check_comment(buf) (((buf)[0] == '/') && ((buf)[1] == '/'))
+#define __skip_space(str) while (*(str) == ' ') ((str)++)
+
+static int ath_parse_ps(FILE *stream)
+{
+ char buf[LINE_SIZE_MAX + 1];
+ char *ptr;
+ uint8_t tag_cnt = 0;
+ int16_t byte_count = 0;
+ struct ps_entry_type format;
+ struct tag_info status = { 0, 0, 0, 0 };
+
+ do {
+ int read_count;
+ struct ps_cfg_entry *tag;
+
+ ptr = fgets(buf, LINE_SIZE_MAX, stream);
+ if (!ptr)
+ break;
+
+ __skip_space(ptr);
+ if (__check_comment(ptr))
+ continue;
+
+ /* Lines with a '#' will be followed by new PS entry */
+ if (ptr == strstr(ptr, "#")) {
+ if (status.section != PS_UNDEF) {
+ return -EILSEQ;
+ } else {
+ status.section = PS_ID;
+ continue;
+ }
+ }
+
+ tag = &ps_list[tag_cnt];
+
+ switch (status.section) {
+ case PS_ID:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ tag->id = read_data_in_section(ptr, format);
+ status.section = PS_LEN;
+ break;
+
+ case PS_LEN:
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ byte_count = read_data_in_section(ptr, format);
+ if (byte_count > PS_MAX_LEN)
+ return -EILSEQ;
+
+ tag->len = byte_count;
+ tag->data = (uint8_t *)malloc(byte_count);
+
+ status.section = PS_DATA;
+ status.line_count = 0;
+ break;
+
+ case PS_DATA:
+ if (status.line_count == 0)
+ if (get_input_format(ptr, &format) < 0)
+ return -EILSEQ;
+
+ __skip_space(ptr);
+
+ status.char_cnt = update_char_count(ptr);
+
+ read_count = (byte_count > ENTRY_PER_LINE) ?
+ ENTRY_PER_LINE : byte_count;
+
+ if (format.type == PS_HEX && format.array == TRUE) {
+ while (read_count > 0) {
+ update_tag_data(tag, &status, ptr);
+ read_count -= 2;
+ }
+
+ if (byte_count > ENTRY_PER_LINE)
+ byte_count -= ENTRY_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ status.line_count++;
+
+ if (byte_count == 0)
+ memset(&status, 0x00, sizeof(struct tag_info));
+
+ if (status.section == PS_UNDEF)
+ tag_cnt++;
+
+ if (tag_cnt == MAX_TAGS)
+ return -EILSEQ;
+ break;
+ }
+ } while (ptr);
+
+ return tag_cnt;
+}
+
+#define MAX_PATCH_CMD 244
+struct patch_entry {
+ int16_t len;
+ uint8_t data[MAX_PATCH_CMD];
+};
+
+static int ps_patch_download(int fd, FILE *stream)
+{
+ char byte[3];
+ char ptr[MAX_PATCH_CMD + 1];
+ int byte_cnt;
+ int patch_count = 0;
+
+ byte[2] = '\0';
+
+ while (fgets(ptr, MAX_PATCH_CMD, stream)) {
+ if (strlen(ptr) <= 1 || !isxdigit(ptr[0]))
+ continue;
+ else
+ break;
+ }
+
+ byte_cnt = strtol(ptr, NULL, 16);
+
+ while (byte_cnt > 0) {
+ int i;
+ uint8_t cmd[HCI_MAX_CMD_SIZE];
+ struct patch_entry patch;
+
+ if (byte_cnt > MAX_PATCH_CMD)
+ patch.len = MAX_PATCH_CMD;
+ else
+ patch.len = byte_cnt;
+
+ for (i = 0; i < patch.len; i++) {
+ if (!fgets(byte, 3, stream))
+ return -1;
+
+ patch.data[i] = strtoul(byte, NULL, 16);
+ }
+
+ load_hci_ps_hdr(cmd, WRITE_PATCH, patch.len, patch_count);
+ memcpy(&cmd[HCI_PS_CMD_HDR_LEN], patch.data, patch.len);
+
+ if (write_cmd(fd, cmd, patch.len + HCI_PS_CMD_HDR_LEN) < 0)
+ return -1;
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_PATCH_CMD;
+ }
+
+ if (write_ps_cmd(fd, ENABLE_PATCH, 0) < 0)
+ return -1;
+
+ return patch_count;
+}
+
+#define PS_RAM_SIZE 2048
+
+static int ps_config_download(int fd, int tag_count)
+{
+
+ if (write_ps_cmd(fd, PS_RESET, PS_RAM_SIZE) < 0)
+ return -1;
+
+ if (tag_count > 0)
+ if (write_ps_cmd(fd, PS_WRITE, tag_count) < 0)
+ return -1;
+ return 0;
+}
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+
+static void get_ps_file_name(int devtype, int rom_version, char *path)
+{
+ char *filename;
+
+ if (devtype == 0xdeadc0de)
+ filename = PS_ASIC_FILE;
+ else
+ filename = PS_FPGA_FILE;
+
+ snprintf(path, MAXPATHLEN, "%s%x/%s", FW_PATH, rom_version, filename);
+}
+
+#define PATCH_FILE "RamPatch.txt"
+#define FPGA_ROM_VERSION 0x99999999
+#define ROM_DEV_TYPE 0xdeadc0de
+
+static void get_patch_file_name(int dev_type, int rom_version,
+ int build_version, char *path)
+{
+
+ if (rom_version == FPGA_ROM_VERSION && dev_type != ROM_DEV_TYPE &&
+ dev_type != 0 && build_version == 1)
+ path[0] = '\0';
+ else
+ snprintf(path, MAXPATHLEN, "%s%x/%s",
+ FW_PATH, rom_version, PATCH_FILE);
+}
+
+#define VERIFY_CRC 9
+#define PS_REGION 1
+#define PATCH_REGION 2
+
+static int get_ar3k_crc(int dev)
+{
+ uint8_t cmd[7];
+ uint8_t *event;
+ int err;
+
+ load_hci_ps_hdr(cmd, VERIFY_CRC, 0, PS_REGION | PATCH_REGION);
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+ /* Send error code if CRC check patched */
+ if (read_ps_event(event, HCI_PS_CMD_OCF) >= 0)
+ err = -EILSEQ;
+
+ if (!event)
+ free(event);
+
+ return err;
+}
+
+#define DEV_REGISTER 0x4FFC
+#define GET_DEV_TYPE_OCF 0x05
+
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t cmd[8];
+ uint8_t *event;
+ uint32_t reg;
+ int err;
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ GET_DEV_TYPE_OCF));
+ ch->plen = 5;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = (uint8_t)DEV_REGISTER;
+ ptr[1] = (uint8_t)DEV_REGISTER >> 8;
+ ptr[2] = (uint8_t)DEV_REGISTER >> 16;
+ ptr[3] = (uint8_t)DEV_REGISTER >> 24;
+ ptr[4] = 0x04;
+
+ err = send_hci_cmd_sync(dev, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, GET_DEV_TYPE_OCF);
+ if (err < 0)
+ goto cleanup;
+
+ reg = event[10];
+ reg = (reg << 8) | event[9];
+ reg = (reg << 8) | event[8];
+ reg = (reg << 8) | event[7];
+ *code = reg;
+
+cleanup:
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define GET_VERSION_OCF 0x1E
+
+static int read_ar3k_version(int pConfig, int *rom_version, int *build_version)
+{
+ uint8_t cmd[3];
+ uint8_t *event;
+ int err;
+ int status;
+ hci_command_hdr *ch = (void *)cmd;
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ GET_VERSION_OCF));
+ ch->plen = 0;
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, GET_VERSION_OCF);
+ if (err < 0)
+ goto cleanup;
+
+ status = event[10];
+ status = (status << 8) | event[9];
+ status = (status << 8) | event[8];
+ status = (status << 8) | event[7];
+ *rom_version = status;
+
+ status = event[14];
+ status = (status << 8) | event[13];
+ status = (status << 8) | event[12];
+ status = (status << 8) | event[11];
+ *build_version = status;
+
+cleanup:
+ if (event)
+ free(event);
+
+ return err;
+}
+
+static void convert_bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ int colon_present = 0;
+
+ if (strstr(str_bdaddr, ":"))
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ /* Reverse the BDADDR to LSB first */
+ for (i = 0, j = 5; i < 6; i++, j--) {
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t *event;
+ int err;
+ uint8_t cmd[13];
+ uint8_t *ptr = cmd;
+ hci_command_hdr *ch = (void *)cmd;
+
+ memset(cmd, 0, sizeof(cmd));
+
+ ch->opcode = htobs(cmd_opcode_pack(HCI_VENDOR_CMD_OGF,
+ HCI_PS_CMD_OCF));
+ ch->plen = 10;
+ ptr += HCI_COMMAND_HDR_SIZE;
+
+ ptr[0] = 0x01;
+ ptr[1] = 0x01;
+ ptr[2] = 0x00;
+ ptr[3] = 0x06;
+
+ convert_bdaddr(bdaddr, (char *)&ptr[4]);
+
+ err = send_hci_cmd_sync(pConfig, cmd, sizeof(cmd), &event);
+ if (err < 0)
+ return err;
+
+ err = read_ps_event(event, HCI_PS_CMD_OCF);
+
+ if (event)
+ free(event);
+
+ return err;
+}
+
+#define HCI_SLEEP_CMD_OCF 0x04
+
+int ath_configure_sleep(int fd, int sleep_stat)
+{
+ int dev_id, dd;
+ struct timespec tm = { 0, 50000 };
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return dev_id;
+ }
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return dd;
+ }
+
+ sleep(2);
+
+ /* send vendor specific command with Sleep feature Enabled */
+ if (hci_send_cmd(dd, OGF_VENDOR_CMD, HCI_SLEEP_CMD_OCF,
+ 1, &sleep_stat) < 0)
+ perror("Power management Disabled");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+static void write_bdaddr_from_file(int rom_version, int fd)
+{
+ FILE *stream;
+ char bdaddr[PATH_MAX];
+ char bdaddr_file[PATH_MAX];
+
+ snprintf(bdaddr_file, MAXPATHLEN, "%s%x/%s",
+ FW_PATH, rom_version, BDADDR_FILE);
+
+ stream = fopen(bdaddr_file, "r");
+ if (!stream)
+ return;
+
+ if (fgets(bdaddr, PATH_MAX - 1, stream))
+ write_bdaddr(fd, bdaddr);
+
+ fclose(stream);
+}
+
+int ath_ps_download(int fd)
+{
+ int err = 0;
+ int tag_count;
+ int patch_count = 0;
+ int rom_version = 0;
+ int build_version = 0;
+ uint32_t dev_type = 0;
+ char patch_file[PATH_MAX];
+ char ps_file[PATH_MAX];
+ FILE *stream;
+
+ /*
+ * Verfiy firmware version. depending on it select the PS
+ * config file to download.
+ */
+ if (get_device_type(fd, &dev_type) < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ if (read_ar3k_version(fd, &rom_version, &build_version) < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ /* Do not download configuration if CRC passes */
+ if (get_ar3k_crc(fd) < 0) {
+ err = 0;
+ goto download_cmplete;
+ }
+
+ get_ps_file_name(dev_type, rom_version, ps_file);
+ get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+
+ stream = fopen(ps_file, "r");
+ if (!stream) {
+ perror("firmware file open error\n");
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+ tag_count = ath_parse_ps(stream);
+
+ fclose(stream);
+
+ if (tag_count < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if patch file is not available.
+ */
+ if (patch_file[0] == '\0')
+ err = 0;
+
+ stream = fopen(patch_file, "r");
+ if (!stream)
+ err = 0;
+ else {
+ patch_count = ps_patch_download(fd, stream);
+ fclose(stream);
+
+ if (patch_count < 0) {
+ err = -EILSEQ;
+ goto download_cmplete;
+ }
+ }
+
+ err = ps_config_download(fd, tag_count);
+
+download_cmplete:
+ if (!err)
+ write_bdaddr_from_file(rom_version, fd);
+
+ return err;
+}
--
1.7.0.4
^ permalink raw reply related
* [PATCH v2 1/2] Bluetooth: Option to enable power management from host
From: Suraj Sumangala @ 2010-08-13 6:36 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jothikumar.Mothilal, Suraj Sumangala
This provides a new option for hciattach to enable hardware specific
power management from host.
This option by default will be disabled for existing devices
---
tools/hciattach.8 | 13 ++++++++
tools/hciattach.c | 88 ++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 76 insertions(+), 25 deletions(-)
diff --git a/tools/hciattach.8 b/tools/hciattach.8
index 9bd1538..f443dff 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -122,7 +122,20 @@ the serial link (
set by default. To force no flow control use
.B noflow
instead.
+.TP
+.I sleep
+Enables hardware specific power management feature. If
+.I sleep
+is appended to the list of options then this feature is enabled. To disable
+this feature use
+.B nosleep
+instead.
+All above mentioned device types have
+.B nosleep
+set by default.
+Note: This option will only be valid for hardware which support
+hardware specific power management enable option from host.
.TP
.I bdaddr
The
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 81aea7b..8616899 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -63,12 +63,15 @@ struct uart_t {
int init_speed;
int speed;
int flags;
+ int pm;
char *bdaddr;
int (*init) (int fd, struct uart_t *u, struct termios *ti);
int (*post) (int fd, struct uart_t *u, struct termios *ti);
};
#define FLOW_CTL 0x0001
+#define ENABLE_PM 1
+#define DISABLE_PM 0
static volatile sig_atomic_t __io_canceled = 0;
@@ -1006,72 +1009,100 @@ static int bcm2035(int fd, struct uart_t *u, struct termios *ti)
}
struct uart_t uart[] = {
- { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
- { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, ericsson },
- { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200, FLOW_CTL, NULL, digi },
+ { "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
- { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "ericsson", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, ericsson },
+
+ { "digi", 0x0000, 0x0000, HCI_UART_H4, 9600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, digi },
+
+ { "bcsp", 0x0000, 0x0000, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Xircom PCMCIA cards: Credit Card Adapter and Real Port Adapter */
- { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "xircom", 0x0105, 0x080a, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* CSR Casira serial adapter or BrainBoxes serial dongle (BL642) */
- { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+ { "csr", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* BrainBoxes PCMCIA card (BL620) */
- { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, csr },
+ { "bboxes", 0x0160, 0x0002, HCI_UART_H4, 115200, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* Silicon Wave kits */
- { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, swave },
+ { "swave", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, swave },
/* Texas Instruments Bluelink (BRF) modules */
- { "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texas, texas2 },
- { "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200, FLOW_CTL, NULL, texasalt, NULL },
+ { "texas", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, texas, texas2 },
+
+ { "texasalt", 0x0000, 0x0000, HCI_UART_LL, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, texasalt, NULL },
/* ST Microelectronics minikits based on STLC2410/STLC2415 */
- { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200, FLOW_CTL, NULL, st },
+ { "st", 0x0000, 0x0000, HCI_UART_H4, 57600, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, st },
/* ST Microelectronics minikits based on STLC2500 */
- { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "00:80:E1:00:AB:BA", stlc2500 },
+ { "stlc2500", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, "00:80:E1:00:AB:BA", stlc2500 },
/* Philips generic Ericsson IP core based */
- { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "philips", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* Philips BGB2xx Module */
- { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, "BD:B2:10:00:AB:BA", bgb2xx },
+ { "bgb2xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, "BD:B2:10:00:AB:BA", bgb2xx },
/* Sphinx Electronics PICO Card */
- { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "picocard", 0x025e, 0x1000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* Inventel BlueBird Module */
- { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, NULL },
+ { "inventel", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, NULL },
/* COM One Platinium Bluetooth PC Card */
- { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "comone", 0xffff, 0x0101, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* TDK Bluetooth PC Card and IBM Bluetooth PC Card II */
- { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "tdk", 0x0105, 0x4254, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Socket Bluetooth CF Card (Rev G) */
- { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400, 0, NULL, bcsp },
+ { "socket", 0x0104, 0x0096, HCI_UART_BCSP, 230400, 230400,
+ 0, DISABLE_PM, NULL, bcsp },
/* 3Com Bluetooth Card (Version 3.0) */
- { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200, FLOW_CTL, NULL, csr },
+ { "3com", 0x0101, 0x0041, HCI_UART_H4, 115200, 115200,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* AmbiCom BT2000C Bluetooth PC/CF Card */
- { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800, FLOW_CTL, NULL, csr },
+ { "bt2000c", 0x022d, 0x2000, HCI_UART_H4, 57600, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, csr },
/* Zoom Bluetooth PCMCIA Card */
- { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "zoom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Sitecom CN-504 PCMCIA Card */
- { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "sitecom", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Billionton PCBTC1 PCMCIA Card */
- { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
+ { "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200,
+ 0, DISABLE_PM, NULL, bcsp },
/* Broadcom BCM2035 */
- { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
+ { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800,
+ FLOW_CTL, DISABLE_PM, NULL, bcm2035 },
{ NULL, 0 }
};
@@ -1290,6 +1321,13 @@ int main(int argc, char *argv[])
break;
case 4:
+ if (!strcmp("sleep", argv[optind]))
+ u->pm = ENABLE_PM;
+ else
+ u->pm = DISABLE_PM;
+ break;
+
+ case 5:
u->bdaddr = argv[optind];
break;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH] Fix unnecessary checking for empty phones list
From: Radoslaw Jablonski @ 2010-08-13 6:35 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Radoslaw Jablonski
Removed not needed anymore checking for empty list of phone numbers.
---
plugins/vcard.c | 5 -----
1 files changed, 0 insertions(+), 5 deletions(-)
diff --git a/plugins/vcard.c b/plugins/vcard.c
index 9beb62a..80f8265 100644
--- a/plugins/vcard.c
+++ b/plugins/vcard.c
@@ -295,11 +295,6 @@ static void vcard_printf_end(GString *vcards)
void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
uint64_t filter, uint8_t format)
{
- /* There's really nothing to do */
- if ((contact->numbers == NULL && (contact->fullname == NULL ||
- contact->fullname[0] == '\0')))
- return;
-
if (format == FORMAT_VCARD30)
filter |= (FILTER_VERSION | FILTER_FN | FILTER_N | FILTER_TEL);
else if (format == FORMAT_VCARD21)
--
1.7.0.4
^ permalink raw reply related
* bluetooth profile source code
From: Viral Mehta @ 2010-08-13 4:34 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Hi,
I am looking for some BT profile source code.
I was able to find out for OBEX source code,
But, I could not find any source cod for
Headset Profile
A2DP profile
HandsFree Profile
Surprisingly, is there no open source code for all these profiles ?
Or I am just not able to google properly !!??
Thanks,
Viral
This Email may contain confidential or privileged information for the intended recipient (s) If you are not the intended recipient, please do not use or disseminate the information, notify the sender and delete it from your system.
______________________________________________________________________
^ permalink raw reply
* Re: why is hciops a plugin ?
From: Pavan Savoy @ 2010-08-13 0:35 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: Johan Hedberg, linux-bluetooth@vger.kernel.org
In-Reply-To: <1281613392.12579.267.camel@localhost.localdomain>
Marcel, Johan,
On Thu, Aug 12, 2010 at 5:13 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Johan,
>
>> > When you say raw HCI access do you mean doing the
>> > socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI) and bind/ioctl, writev+poll/read
>> > lacks few things ?
>> > but all of these are in lib/hci isn't it ?
>>
>> Yes, that's the type of socket that I meant. Direct access to the HCI
>> messages would largely go away from the userspace side. Those
>> libbluetooth functions you're referring to are just convenience wrappers
>> for sending HCI commands through raw HCI sockets.
>>
>> > So even if it was netlink only something like hci_open_dev() would
>> > have changed to socket(PF_NETLINK, SOCK_RAW, BT_NETLINK ); or
>> > something right ?
>>
>> I'm not really familiar enough with netlink to comment on this. Marcel
>> (whose idea it originally was) would have to comment.
>>
>> > any pointers out there ? references for such things ?
>> > I am just curious, don;t want anything specific ...
>>
>> Right now, not really. The only stack internal messages there are at the
>> moment are things like HCI_DEV_REG, HCI_DEV_UNREG, HCI_DEV_UP and
>> HCI_DEV_DOWN and they only go one way (kernel->userspace). This category
>> of messages will grow in the future and it'll be possible to send them
>> both ways.
Yes, this explains why hciops is a a plugin now, thanks...
>> Some HCI messages for which it's already clear now that there will be a
>> benefit from a higher level abstraction on the userspace side are things
>> like name resolving and pairing related requests. Also, if I understood
>> correctly from Marcel, removing userspace processing of HCI events will
>> result in a considreable reduction of context switches since there wont
>> anymore be a promiscuous userspace-side socket that needs to
>> handle/filter all HCI data (Marcel, please correct me if this is
>> inaccurate or wrong).
>
> this is correct. We will not require userspace to do HCI event
> processing and filtering anymore. It will be a dedicated side channel.
Side channel ? But there would still be some way to bring out events
onto user-space right ?
As in application which do and ONLY do HCI-VS commands, and are
interested in HCI-VS events...
> Regards
>
> Marcel
>
>
>
^ permalink raw reply
* Re: [RFC 6/7] Bluetooth: Reassemble enhanced L2CAP PDUs using skb fragments.
From: Mat Martineau @ 2010-08-13 0:11 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: linux-bluetooth, marcel, rshaffer
In-Reply-To: <20100811052433.GA10773@vigoh>
Gustavo -
On Wed, 11 Aug 2010, Gustavo F. Padovan wrote:
> Hi Mat,
>
> * Mat Martineau <mathewm@codeaurora.org> [2010-08-10 12:15:03 -0700]:
>
>> As enhanced L2CAP PDUs arrive, it is not necessary to copy them
>> in to a separate skbuff. Instead, the skbuffs can be linked
>> together as fragments, only being copied in to a linear buffer
>> when the data is copied to userspace. This avoids the need
>> to allocate additional buffers for incoming data, and
>> eliminates copying of data payloads during SDU reassembly.
>> This is of greater concern with high-speed AMP links than
>> with BR/EDR.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> include/net/bluetooth/l2cap.h | 1 +
>> net/bluetooth/l2cap.c | 66 +++++++++++++++++++++-------------------
>> 2 files changed, 36 insertions(+), 31 deletions(-)
>>
>> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
>> index 2f3222f..9384e87 100644
>> --- a/include/net/bluetooth/l2cap.h
>> +++ b/include/net/bluetooth/l2cap.h
>> @@ -357,6 +357,7 @@ struct l2cap_pinfo {
>> __u16 sdu_len;
>> __u16 partial_sdu_len;
>> struct sk_buff *sdu;
>> + struct sk_buff *sdu_last_frag;
>>
>> __u8 ident;
>>
>> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
>> index b485c4a..0212035 100644
>> --- a/net/bluetooth/l2cap.c
>> +++ b/net/bluetooth/l2cap.c
>> @@ -290,6 +290,9 @@ static void l2cap_chan_del(struct sock *sk, int err)
>> skb_queue_purge(SREJ_QUEUE(sk));
>> skb_queue_purge(BUSY_QUEUE(sk));
>>
>> + if (l2cap_pi(sk)->sdu)
>> + kfree_skb(l2cap_pi(sk)->sdu);
>> +
>> list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) {
>> list_del(&l->list);
>> kfree(l);
>> @@ -3635,6 +3638,27 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s
>> return 0;
>> }
>>
>> +static inline void append_skb_frag(struct sk_buff *skb,
>> + struct sk_buff *new_frag, struct sk_buff **last_frag)
>
> Call this l2cap_append_skb_frag()
Ok.
>
>> +{
>> + /* skb->len reflects data in skb as well as all fragments
>> + skb->data_len reflects only data in fragments
>> + */
>> + BT_DBG("skb %p, new_frag %p, *last_frag %p", skb, new_frag, *last_frag);
>> +
>> + if (!skb_has_frags(skb))
>> + skb_shinfo(skb)->frag_list = new_frag;
>> +
>> + new_frag->next = NULL;
>> +
>> + (*last_frag)->next = new_frag;
>> + *last_frag = new_frag;
>> +
>> + skb->len += new_frag->len;
>> + skb->data_len += new_frag->len;
>> + skb->truesize += new_frag->truesize;
>> +}
>> +
>
> Wondering if it is possible to do that append more simple, but I looked
> through the kernel code it's not possible, we have to keep last frag
> pointer.
>
> This change should go to l2cap_streaming_reassembly_sdu() as well, then
> you can get ride of partial_sdu_len in the struct l2cap_pinfo.
I haven't had a chance to test streaming mode, so I was avoiding
changes to it so far. I agree that the same technique can be applied
there.
>
>> static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control)
>> {
>> struct l2cap_pinfo *pi = l2cap_pi(sk);
>> @@ -3643,7 +3667,7 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c
>>
>> switch (control & L2CAP_CTRL_SAR) {
>> case L2CAP_SDU_UNSEGMENTED:
>> - if (pi->conn_state & L2CAP_CONN_SAR_SDU)
>> + if (pi->sdu)
>
> pi->sdu can do the work work of pi->conn_state & L2CAP_CONN_SAR_SDU, so
> a separated patch for that change sounds better (you can change that for
> the Streaming mode at the same time, it's a similar code, but more simple).
>
Ok.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: [RFC 5/7] Bluetooth: Handle fragmented skbs in bt_sock_stream_recvmsg()
From: Mat Martineau @ 2010-08-13 0:07 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: linux-bluetooth, marcel, rshaffer
In-Reply-To: <20100811042543.GA9428@vigoh>
On Wed, 11 Aug 2010, Gustavo F. Padovan wrote:
> Hi Mat,
>
> * Mat Martineau <mathewm@codeaurora.org> [2010-08-10 12:15:02 -0700]:
>
>> When reading L2CAP skbuffs, add the ability to copy from
>> fragmented skbuffs generated during ERTM or streaming mode
>> reassembly. This defers extra copying of L2CAP payloads
>> until the final, unavoidable copy to userspace.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> net/bluetooth/af_bluetooth.c | 30 ++++++++++++++++++++++++++++--
>> 1 files changed, 28 insertions(+), 2 deletions(-)
>>
>> diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
>> index 77a26fe..5e0375b 100644
>> --- a/net/bluetooth/af_bluetooth.c
>> +++ b/net/bluetooth/af_bluetooth.c
>> @@ -342,7 +342,7 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>> }
>>
>> chunk = min_t(unsigned int, skb->len, size);
>> - if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
>> + if (skb_copy_datagram_iovec(skb, 0, msg->msg_iov, chunk)) {
>> skb_queue_head(&sk->sk_receive_queue, skb);
>> if (!copied)
>> copied = -EFAULT;
>> @@ -354,7 +354,33 @@ int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
>> sock_recv_ts_and_drops(msg, sk, skb);
>>
>> if (!(flags & MSG_PEEK)) {
>> - skb_pull(skb, chunk);
>> + int skb_len = skb_headlen(skb);
>
> Why are you using the header length here?
skb_headlen() returns the length of the first fragment.
>> +
>> + if (chunk <= skb_len) {
>> + __skb_pull(skb, chunk);
>> + } else {
>> + struct sk_buff *frag;
>> +
>> + __skb_pull(skb, skb_len);
>> + chunk -= skb_len;
>
> Why do we have this __skb_pull() here? I think skb_walk_frags() can
> handle everything.
That first __skb_pull() is necessary to deal with data in the first
skbuff, and the skb_walk_frags() deals with anything in
skb_shinfo(skb)->frag_list. The linked skb list looks roughly like
this:
skb
unsigned char *data -> (L2CAP data)
struct sk_buff *frag_list -> 2nd frag
unsigned char *data -> (more data)
struct sk_buff *next -> 3rd frag
(etc.)
So the first frag is special - the pointer to the fragment is
frag_list. Each linked fragment after that uses the "next" pointer in
the sk_buff struct. The skb_walk_frags() macro starts with the
sk_buff pointed to by frag_list, then follows the "next" links.
>> +
>> + skb_walk_frags(skb, frag) {
>> + if (chunk <= frag->len) {
>> + /* Pulling partial data */
>> + skb->len -= chunk;
>> + skb->data_len -= chunk;
>> + __skb_pull(frag, chunk);
>> + break;
>
> If we break here what will happen whit the rest of the data to be
> pulled.
The data is left to be pulled later. The skb is not freed until all
the fragments are empty, and this is handled by existing code. I've
added the next couple of lines of context below to help explain.
>
>> + } else if (frag->len) {
>> + /* Pulling all frag data */
>> + chunk -= frag->len;
>> + skb->len -= frag->len;
>> + skb->data_len -= frag->len;
>> + __skb_pull(frag, frag->len);
>> + }
>> + }
>> + }
>> +
>> if (skb->len) {
>> skb_queue_head(&sk->sk_receive_queue, skb);
>> break;
}
kfree_skb(skb);
If the skb is not empty, it's pushed back on the head of the receive
queue. If it is empty, it's freed.
I based this approach on some code I found in the SCTP protocol.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: [RFC 3/7] Bluetooth: Add FCS awareness to L2CAP HCI fragmentation.
From: Mat Martineau @ 2010-08-12 23:36 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: linux-bluetooth, marcel, rshaffer
In-Reply-To: <20100811035654.GA9293@vigoh>
On Wed, 11 Aug 2010, Gustavo F. Padovan wrote:
> Hi Mat,
>
> * Gustavo F. Padovan <gustavo@padovan.org> [2010-08-11 00:35:41 -0300]:
>
>> * Mat Martineau <mathewm@codeaurora.org> [2010-08-10 12:15:00 -0700]:
>>
>>> In order to not limit ERTM and streaming mode PDUs to the HCI MTU
>>> size, L2CAP must be able to split PDUs in to multple HCI fragments.
>>> This is done by allocating space for the FCS in the last fragment.
>>>
>>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>>> ---
>>> net/bluetooth/l2cap.c | 39 ++++++++++++++++++++++++++++++++++-----
>>> 1 files changed, 34 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
>>> index aa69c84..b485c4a 100644
>>> --- a/net/bluetooth/l2cap.c
>>> +++ b/net/bluetooth/l2cap.c
>>> @@ -1664,31 +1664,63 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
>>> {
>>> struct l2cap_conn *conn = l2cap_pi(sk)->conn;
>>> struct sk_buff **frag;
>>> + struct sk_buff *final;
>>> int err, sent = 0;
>>>
>>> + BT_DBG("sk %p, msg %p, len %d, count %d, skb %p", sk,
>>> + msg, (int)len, (int)count, skb);
>>> +
>>> if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
>>> return -EFAULT;
>>>
>>> sent += count;
>>> len -= count;
>>> + final = skb;
>>>
>>> /* Continuation fragments (no L2CAP header) */
>>> frag = &skb_shinfo(skb)->frag_list;
>>> while (len) {
>>> + int skblen;
>>> count = min_t(unsigned int, conn->mtu, len);
>>>
>>> - *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
>>> + /* Add room for the FCS if it fits */
>>> + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16 &&
>>> + len + L2CAP_FCS_SIZE <= conn->mtu)
>>
>> You don't need to check for (len + L2CAP_FCS_SIZE <= conn=mtu) here.
>> Section 5.1 point that:
>>
>> "Unlike the B-Frame length field, the I-frame length field may be greater
>> than the configured MTU because it includes the octet lengths of the
>> Control, L2CAP SDU Length (when present), and frame check sequence
>> fields as well as the Information octets."
>>
>> From that I understand "len <=" and not "len + L2CAP_FCS_SIZE <="
>
> So here you might want to the check if we support FCS, and then add 2 to
> skblen.
That's what the code does, without violating the HCI MTU.
>>> + skblen = count + L2CAP_FCS_SIZE;
>>> + else
>>> + skblen = count;
>>> +
>>> + *frag = bt_skb_send_alloc(sk, skblen,
>>> + msg->msg_flags & MSG_DONTWAIT, &err);
>>> if (!*frag)
>>> return -EFAULT;
>>> - if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
>>> +
>>> + if (memcpy_fromiovec(skb_put(*frag, count),
>>> + msg->msg_iov, count))
>>> return -EFAULT;
>>>
>>> sent += count;
>>> len -= count;
>>>
>>> + final = *frag;
>>> +
>>> frag = &(*frag)->next;
>>> }
>>>
>>> + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
>>> + if (skb_tailroom(final) < L2CAP_FCS_SIZE) {
>>> + *frag = bt_skb_send_alloc(sk, L2CAP_FCS_SIZE,
>>> + msg->msg_flags & MSG_DONTWAIT,
>>> + &err);
>
> Why do we need to check for FCS again? We already added it required
> space to the last fragment.
>
If there was room in the HCI fragment, count+2 bytes were allocated
with bt_skb_send_alloc. However, only count bytes were used by
skb_put.
This final block of code is doing two things:
1. Allocating a final HCI fragment for the FCS if there was not room
for the FCS in the last data fragment.
2. Doing the skb_put for the FCS bytes.
I will add some comments to this code to help clarify what's going on.
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: [RFC 3/7] Bluetooth: Add FCS awareness to L2CAP HCI fragmentation.
From: Mat Martineau @ 2010-08-12 23:26 UTC (permalink / raw)
To: Gustavo F. Padovan; +Cc: linux-bluetooth, marcel, rshaffer
In-Reply-To: <20100811033540.GA9151@vigoh>
On Wed, 11 Aug 2010, Gustavo F. Padovan wrote:
> * Mat Martineau <mathewm@codeaurora.org> [2010-08-10 12:15:00 -0700]:
>
>> In order to not limit ERTM and streaming mode PDUs to the HCI MTU
>> size, L2CAP must be able to split PDUs in to multple HCI fragments.
>> This is done by allocating space for the FCS in the last fragment.
>>
>> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
>> ---
>> net/bluetooth/l2cap.c | 39 ++++++++++++++++++++++++++++++++++-----
>> 1 files changed, 34 insertions(+), 5 deletions(-)
>>
>> diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
>> index aa69c84..b485c4a 100644
>> --- a/net/bluetooth/l2cap.c
>> +++ b/net/bluetooth/l2cap.c
>> @@ -1664,31 +1664,63 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
>> {
>> struct l2cap_conn *conn = l2cap_pi(sk)->conn;
>> struct sk_buff **frag;
>> + struct sk_buff *final;
>> int err, sent = 0;
>>
>> + BT_DBG("sk %p, msg %p, len %d, count %d, skb %p", sk,
>> + msg, (int)len, (int)count, skb);
>> +
>> if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
>> return -EFAULT;
>>
>> sent += count;
>> len -= count;
>> + final = skb;
>>
>> /* Continuation fragments (no L2CAP header) */
>> frag = &skb_shinfo(skb)->frag_list;
>> while (len) {
>> + int skblen;
>> count = min_t(unsigned int, conn->mtu, len);
>>
>> - *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
>> + /* Add room for the FCS if it fits */
>> + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16 &&
>> + len + L2CAP_FCS_SIZE <= conn->mtu)
>
> You don't need to check for (len + L2CAP_FCS_SIZE <= conn=mtu) here.
> Section 5.1 point that:
>
> "Unlike the B-Frame length field, the I-frame length field may be greater
> than the configured MTU because it includes the octet lengths of the
> Control, L2CAP SDU Length (when present), and frame check sequence
> fields as well as the Information octets."
>
> From that I understand "len <=" and not "len + L2CAP_FCS_SIZE <="
This is checking against the HCI MTU, not the L2CAP MTU. Any L2CAP
payload (headers, data, or FCS) needs to fit in the HCI fragment.
The idea here is to see if len is short enough that the FCS can be
included in this HCI fragment after the L2CAP data.
>> + skblen = count + L2CAP_FCS_SIZE;
>> + else
>> + skblen = count;
>> +
>> + *frag = bt_skb_send_alloc(sk, skblen,
>> + msg->msg_flags & MSG_DONTWAIT, &err);
>> if (!*frag)
>> return -EFAULT;
>> - if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
>> +
>> + if (memcpy_fromiovec(skb_put(*frag, count),
>> + msg->msg_iov, count))
>> return -EFAULT;
>>
>> sent += count;
>> len -= count;
>>
>> + final = *frag;
>> +
>> frag = &(*frag)->next;
>> }
>>
>> + if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) {
>> + if (skb_tailroom(final) < L2CAP_FCS_SIZE) {
>> + *frag = bt_skb_send_alloc(sk, L2CAP_FCS_SIZE,
>> + msg->msg_flags & MSG_DONTWAIT,
>> + &err);
>> + if (!*frag)
>> + return -EFAULT;
>> +
>> + final = *frag;
>> + }
>> +
>> + skb_put(final, L2CAP_FCS_SIZE);
>> + }
>> +
>> return sent;
>> }
>>
>> @@ -1790,9 +1822,6 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *m
>> return ERR_PTR(err);
>> }
>>
>> - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16)
>> - put_unaligned_le16(0, skb_put(skb, 2));
>> -
>> bt_cb(skb)->retries = 0;
>> return skb;
>> }
>> --
>> 1.7.1
--
Mat Martineau
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: [PATCH] Bluetooth: Process HCI events in a workqueue instead of a tasklet
From: David Vrabel @ 2010-08-12 22:20 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1281446085.12579.212.camel@localhost.localdomain>
Marcel Holtmann wrote:
> Hi David,
>
>>>> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
>>>> ---
>>>> include/net/bluetooth/hci_core.h | 2 +
>>>> net/bluetooth/hci_core.c | 58 ++++++++++++++++++++++++++++++++-----
>>>> 2 files changed, 52 insertions(+), 8 deletions(-)
>>> so I stuffed this now into bluetooth-testing tree and would like to see
>>> some extra testing exposure. So far this has only been tested by myself.
>>>
>>> If there are no regression then this should make a lot of HCI and L2CAP
>>> handling a lot simple.
>> This may result in packets being processed in a different order to that
>> which they were received in.
>>
>> e.g., what happens to an ACL packet processed before the connection
>> complete event for that connection?
>
> good point. So we would either a) need to disable the RX tasklet when we
> receive an event and schedule it for processing or b) process the ACL
> data also in a workqueue.
I've thought some more about this and I'm not sure disabling the tasklet
is sufficient to prevent packets being reordered. Consider a transport
that submits (in the same interrupt handler call) an ACL packet and an
HCI event. The tasklet will be scheduled and then disabled until the
event is processed in the workqueue.
On the other hand, USB transports do not ensure any ordering between HCI
event and ACL packets because they're received on different USB
endpoints which could be processed in any order.
David
--
David Vrabel, Senior Software Engineer, Drivers
CSR, Churchill House, Cambridge Business Park, Tel: +44 (0)1223 692562
Cowley Road, Cambridge, CB4 0WZ http://www.csr.com/
Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
^ permalink raw reply
* [PATCH 2nd version] IrMC sync server support
From: Marcel Mol @ 2010-08-12 21:09 UTC (permalink / raw)
To: linux-bluetooth
A reasonable working IrMC SYNC server (only full phonebook sync support)
Support for cal and note by just returning nothing.
---
Makefile.am | 3 +
plugins/irmc.c | 507 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.c | 10 +-
src/obex.h | 3 +-
4 files changed, 521 insertions(+), 2 deletions(-)
create mode 100644 plugins/irmc.c
diff --git a/Makefile.am b/Makefile.am
index 73e2f28..a2873f9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,9 @@ builtin_modules += pbap
builtin_sources += plugins/pbap.c plugins/phonebook.h \
plugins/vcard.h plugins/vcard.c
+builtin_modules += irmc
+builtin_sources += plugins/irmc.c plugins/phonebook.h
+
builtin_modules += syncevolution
builtin_sources += plugins/syncevolution.c
diff --git a/plugins/irmc.c b/plugins/irmc.c
new file mode 100644
index 0000000..fa7f91d
--- /dev/null
+++ b/plugins/irmc.c
@@ -0,0 +1,507 @@
+/*
+ *
+ * OBEX IrMC Sync Server
+ *
+ * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "phonebook.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "dbus.h"
+
+#define IRMC_CHANNEL 17
+
+#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\"/> \
+ <uint8 value=\"%u\" name=\"channel\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+ \
+ <attribute id=\"0x0301\"> \
+ <sequence> \
+ <uint8 value=\"0x01\"/> \
+ </sequence> \
+ </attribute> \
+</record>"
+
+
+struct aparam_header {
+ uint8_t tag;
+ uint8_t len;
+ uint8_t val[0];
+} __attribute__ ((packed));
+
+#define DID_LEN 18
+
+struct irmc_session {
+ struct obex_session *os;
+ struct apparam_field *params;
+ uint16_t entries;
+ GString *buffer;
+ char sn[DID_LEN];
+ char did[DID_LEN];
+ char manu[DID_LEN];
+ char model[DID_LEN];
+};
+
+#define IRMC_TARGET_SIZE 9
+
+static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
+ 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
+
+/*
+ * FIXME:
+ * the IrMC specs state the first vcard should be the owner
+ * vcard. As there is no simple way to collect ownerdetails
+ * just create an empty vcard (which is allowed according to the
+ * specs).
+ */
+static const char *owner_vcard =
+ "BEGIN:VCARD\r\n"
+ "VERSION:2.1\r\n"
+ "N:\r\n"
+ "TEL:\r\n"
+ "X-IRMX-LUID:0\r\n"
+ "END:VCARD\r\n";
+
+static void phonebook_size_result(const char *buffer, size_t bufsize,
+ int vcards, int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("vcards %d", vcards);
+
+ irmc->params->maxlistcount = vcards;
+}
+
+static void query_result(const char *buffer, size_t bufsize, int vcards,
+ int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *s, *t;
+
+ DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
+
+ /* first add a 'owner' vcard */
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new(owner_vcard);
+ else
+ irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
+
+ /* loop around buffer and add X-IRMC-LUID attribs */
+ s = buffer;
+ while ((t = strstr(s, "UID:")) != NULL) {
+ /* add upto UID: into buffer */
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ /*
+ * add UID: line into buffer
+ * Not sure if UID is still needed if X-IRMC-LUID is there
+ */
+ s = t;
+ t = strstr(s, "\r\n");
+ t += 2;
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ /* add X-IRMC-LUID with same number as UID */
+ irmc->buffer = g_string_append_len(irmc->buffer,
+ "X-IRMC-LUID:", 12);
+ s += 4; /* point to uid number */
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ s = t;
+ }
+ /* add remaining bit of buffer */
+ irmc->buffer = g_string_append(irmc->buffer, s);
+
+ obex_object_set_io_flags(irmc, G_IO_IN, 0);
+}
+
+static void *irmc_connect(struct obex_session *os, int *err)
+{
+ struct irmc_session *irmc;
+ struct apparam_field *param;
+
+ DBG("");
+
+ manager_register_session(os);
+
+ irmc = g_new0(struct irmc_session, 1);
+ irmc->os = os;
+
+ /*
+ * FIXME:
+ * Ideally get capabilities info here and use that to define
+ * IrMC DID and SN etc parameters.
+ * For now lets used hostname and some 'random' value
+ */
+ gethostname(irmc->did, DID_LEN);
+ strncpy(irmc->sn, "12345", DID_LEN);
+ strncpy(irmc->manu, "obex", DID_LEN);
+ strncpy(irmc->model, "mymodel", DID_LEN);
+
+ /*
+ * We need to know the number of contact/cal/nt entries
+ * somewhere so why not do it now.
+ */
+ param = g_new0(struct apparam_field, 1);
+ param->maxlistcount = 0; /* to count the number of vcards... */
+ param->filter = 0x200085; /* UID TEL N VERSION */
+ irmc->params = param;
+ phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
+ irmc);
+
+ if (err)
+ *err = 0;
+
+ return irmc;
+}
+
+static int irmc_get(struct obex_session *os, obex_object_t *obj,
+ gboolean *stream, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *type = obex_get_type(os);
+ const char *name = obex_get_name(os);
+ char *path;
+ int ret;
+
+ DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
+
+ path = g_strdup(name);
+ *stream = TRUE;
+
+ ret = obex_get_stream_start(os, path);
+
+ g_free(path);
+
+ return ret;
+}
+
+static void irmc_disconnect(struct obex_session *os, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("");
+
+ manager_unregister_session(os);
+
+ if (irmc->params) {
+ if (irmc->params->searchval)
+ g_free(irmc->params->searchval);
+ g_free(irmc->params);
+ }
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ g_free(irmc);
+}
+
+static int irmc_chkput(struct obex_session *os, void *user_data)
+{
+ DBG("");
+ /* Reject all PUTs */
+ return -EBADR;
+}
+
+static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+{
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ g_string_append_printf(irmc->buffer,
+ "MANU:%s\r\n"
+ "MOD:%s\r\n"
+ "SN:%s\r\n"
+ "PB-TYPE-TX:VCARD2.1\r\n",
+ irmc->manu, irmc->model, irmc->sn);
+
+ return irmc;
+}
+
+static void *irmc_open_pb(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ GString *mybuf;
+ int ret;
+
+ if (!g_strcmp0(name, ".vcf")) {
+ /* how can we tell if the vcard count call already finished? */
+ ret = phonebook_pull("telecom/pb.vcf", irmc->params,
+ query_result, irmc);
+ if (ret < 0) {
+ DBG("phonebook_pull failed...");
+ goto fail;
+ }
+ return irmc;
+ }
+
+ if (!g_strcmp0(name, "/info.log")) {
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "DID:%s\r\n",
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount, irmc->did);
+ }
+ else if (!strncmp(name, "/luid/", 6)) {
+ name += 6;
+ if (!g_strcmp0(name, "cc.log")) {
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
+ }
+ else {
+ int l = strlen(name);
+ /* FIXME:
+ * Reply the same to any *.log so we hopefully force a
+ * full phonebook dump.
+ * Is IEL:2 ok?
+ */
+ if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
+ DBG("changelog request, force whole book");
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "SN:%s\r\n"
+ "IEL:2\r\n"
+ "DID:%s\r\n"
+ "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "*\r\n",
+ irmc->sn, irmc->did,
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount);
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+ }
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ if (!irmc->buffer)
+ irmc->buffer = mybuf;
+ else {
+ irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
+ string_free(mybuf);
+ }
+
+ return irmc;
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static void *irmc_open_cal(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ /* no suport yet. Just return an empty buffer. cal.vcs */
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ return irmc;
+}
+
+static void *irmc_open_nt(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ /* no suport yet. Just return an empty buffer. nt.vnt */
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ return irmc;
+}
+
+static void *irmc_open(const char *name, int oflag, mode_t mode,
+ void *context, size_t *size, int *err)
+{
+ struct irmc_session *irmc = context;
+ int ret;
+ const char *p;
+
+ DBG("name %s context %p", name, context);
+ if (oflag != O_RDONLY) {
+ ret = -EPERM;
+ goto fail;
+ }
+ if (strncmp(name, "telecom/", 8) != 0) {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ p = name + 8;
+ if (!g_strcmp0(p, "devinfo.txt"))
+ return irmc_open_devinfo(irmc, err);
+ else if (!strncmp(p, "pb", 2))
+ return irmc_open_pb(p+2, irmc, err);
+ else if (!strncmp(p, "cal", 3))
+ return irmc_open_cal(p+3, irmc, err);
+ else if (!strncmp(p, "nt", 2))
+ return irmc_open_nt(p+2, irmc, err);
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static int irmc_close(void *object)
+{
+ struct irmc_session *irmc = object;
+
+ DBG("");
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ return 0;
+}
+
+static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
+{
+ struct irmc_session *irmc = object;
+ int len;
+
+ DBG("buffer %p count %d", irmc->buffer, count);
+ if (!irmc->buffer)
+ return -EAGAIN;
+
+ *hi = OBEX_HDR_BODY;
+ len = string_read(irmc->buffer, buf, count);
+ DBG("returning %d bytes", len);
+ return len;
+}
+
+static struct obex_mime_type_driver irmc_driver = {
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .open = irmc_open,
+ .close = irmc_close,
+ .read = irmc_read,
+};
+
+static struct obex_service_driver irmc = {
+ .name = "IRMC Sync server",
+ .service = OBEX_IRMC,
+ .channel = IRMC_CHANNEL,
+ .record = IRMC_RECORD,
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .connect = irmc_connect,
+ .get = irmc_get,
+ .disconnect = irmc_disconnect,
+ .chkput = irmc_chkput
+};
+
+static int irmc_init(void)
+{
+ int err;
+
+ DBG("");
+ err = phonebook_init();
+ if (err < 0)
+ goto fail_pb_init;
+
+ err = obex_mime_type_driver_register(&irmc_driver);
+ if (err < 0)
+ goto fail_mime_irmc;
+
+ err = obex_service_driver_register(&irmc);
+ if (err < 0)
+ goto fail_irmc_reg;
+
+ return 0;
+
+fail_irmc_reg:
+ obex_mime_type_driver_unregister(&irmc_driver);
+fail_mime_irmc:
+ phonebook_exit();
+fail_pb_init:
+ return err;
+}
+
+static void irmc_exit(void)
+{
+ DBG("");
+ obex_service_driver_unregister(&irmc);
+ obex_mime_type_driver_unregister(&irmc_driver);
+ phonebook_exit();
+}
+
+OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
diff --git a/src/main.c b/src/main.c
index 649acf9..ef894cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -80,6 +80,7 @@ static gboolean option_autoaccept = FALSE;
static gboolean option_opp = FALSE;
static gboolean option_ftp = FALSE;
static gboolean option_pbap = FALSE;
+static gboolean option_irmc = FALSE;
static gboolean option_pcsuite = FALSE;
static gboolean option_symlinks = FALSE;
static gboolean option_syncevolution = FALSE;
@@ -120,6 +121,8 @@ static GOptionEntry options[] = {
"Enable Phonebook Access server" },
{ "pcsuite", 's', 0, G_OPTION_ARG_NONE, &option_pcsuite,
"Enable PC Suite Services server" },
+ { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
+ "Enable IrMCSync server" },
{ "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
"Enable OBEX server for SyncEvolution" },
{ NULL },
@@ -208,9 +211,10 @@ int main(int argc, char *argv[])
if (option_opp == FALSE && option_ftp == FALSE &&
option_pbap == FALSE &&
+ option_irmc == FALSE &&
option_syncevolution == FALSE) {
fprintf(stderr, "No server selected (use either "
- "--opp, --ftp, --pbap or --syncevolution)\n");
+ "--opp, --ftp, --pbap, --irmc or --syncevolution)\n");
exit(EXIT_FAILURE);
}
@@ -266,6 +270,10 @@ int main(int argc, char *argv[])
option_autoaccept, option_symlinks,
option_capability);
+ if (option_irmc == TRUE)
+ obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
+ option_capability);
+
if (option_syncevolution == TRUE)
obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
FALSE, NULL);
diff --git a/src/obex.h b/src/obex.h
index 9424b6b..35723ca 100644
--- a/src/obex.h
+++ b/src/obex.h
@@ -34,7 +34,8 @@
#define OBEX_BIP (1 << 3)
#define OBEX_PBAP (1 << 4)
#define OBEX_PCSUITE (1 << 5)
-#define OBEX_SYNCEVOLUTION (1 << 6)
+#define OBEX_IRMC (1 << 6)
+#define OBEX_SYNCEVOLUTION (1 << 7)
#define TARGET_SIZE 16
--
1.7.2
^ permalink raw reply related
* [PATCH 3th version] IrMC sync server support
From: Marcel Mol @ 2010-08-12 21:09 UTC (permalink / raw)
To: linux-bluetooth
A reasonable working IrMC SYNC server (only full phonebook sync support)
Support for cal and note by just returning nothing.
---
Makefile.am | 3 +
plugins/irmc.c | 515 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/main.c | 10 +-
src/obex.h | 3 +-
4 files changed, 529 insertions(+), 2 deletions(-)
create mode 100644 plugins/irmc.c
diff --git a/Makefile.am b/Makefile.am
index 73e2f28..07fc27d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,6 +55,9 @@ builtin_modules += pbap
builtin_sources += plugins/pbap.c plugins/phonebook.h \
plugins/vcard.h plugins/vcard.c
+builtin_modules += irmc
+builtin_sources += plugins/irmc.c
+
builtin_modules += syncevolution
builtin_sources += plugins/syncevolution.c
diff --git a/plugins/irmc.c b/plugins/irmc.c
new file mode 100644
index 0000000..056a3b9
--- /dev/null
+++ b/plugins/irmc.c
@@ -0,0 +1,515 @@
+/*
+ *
+ * OBEX IrMC Sync Server
+ *
+ * Copyright (C) 2010 Marcel Mol <marcel@mesa.nl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <openobex/obex.h>
+#include <openobex/obex_const.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "phonebook.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "dbus.h"
+
+#define IRMC_CHANNEL 17
+
+#define IRMC_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?> \
+<record> \
+ <attribute id=\"0x0001\"> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0004\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x0100\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0003\"/> \
+ <uint8 value=\"%u\" name=\"channel\"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value=\"0x0008\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0009\"> \
+ <sequence> \
+ <sequence> \
+ <uuid value=\"0x1104\"/> \
+ <uint16 value=\"0x0100\" name=\"version\"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id=\"0x0100\"> \
+ <text value=\"%s\" name=\"name\"/> \
+ </attribute> \
+ \
+ <attribute id=\"0x0301\"> \
+ <sequence> \
+ <uint8 value=\"0x01\"/> \
+ </sequence> \
+ </attribute> \
+</record>"
+
+
+struct aparam_header {
+ uint8_t tag;
+ uint8_t len;
+ uint8_t val[0];
+} __attribute__ ((packed));
+
+#define DID_LEN 18
+
+struct irmc_session {
+ struct obex_session *os;
+ struct apparam_field *params;
+ uint16_t entries;
+ GString *buffer;
+ char sn[DID_LEN];
+ char did[DID_LEN];
+ char manu[DID_LEN];
+ char model[DID_LEN];
+};
+
+#define IRMC_TARGET_SIZE 9
+
+static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
+ 0x49, 0x52, 0x4d, 0x43, 0x2d, 0x53, 0x59, 0x4e, 0x43 };
+
+/*
+ * FIXME:
+ * the IrMC specs state the first vcard should be the owner
+ * vcard. As there is no simple way to collect ownerdetails
+ * just create an empty vcard (which is allowed according to the
+ * specs).
+ */
+static const char *owner_vcard =
+ "BEGIN:VCARD\r\n"
+ "VERSION:2.1\r\n"
+ "N:\r\n"
+ "TEL:\r\n"
+ "X-IRMX-LUID:0\r\n"
+ "END:VCARD\r\n";
+
+static void phonebook_size_result(const char *buffer, size_t bufsize,
+ int vcards, int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("vcards %d", vcards);
+
+ irmc->params->maxlistcount = vcards;
+}
+
+static void query_result(const char *buffer, size_t bufsize, int vcards,
+ int missed, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *s, *t;
+
+ DBG("bufsize %d vcards %d missed %d", bufsize, vcards, missed);
+
+ /* first add a 'owner' vcard */
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new(owner_vcard);
+ else
+ irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
+
+ /* loop around buffer and add X-IRMC-LUID attribs */
+ s = buffer;
+ while ((t = strstr(s, "UID:")) != NULL) {
+ /* add upto UID: into buffer */
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ /*
+ * add UID: line into buffer
+ * Not sure if UID is still needed if X-IRMC-LUID is there
+ */
+ s = t;
+ t = strstr(s, "\r\n");
+ t += 2;
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ /* add X-IRMC-LUID with same number as UID */
+ irmc->buffer = g_string_append_len(irmc->buffer,
+ "X-IRMC-LUID:", 12);
+ s += 4; /* point to uid number */
+ irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+ s = t;
+ }
+ /* add remaining bit of buffer */
+ irmc->buffer = g_string_append(irmc->buffer, s);
+
+ obex_object_set_io_flags(irmc, G_IO_IN, 0);
+}
+
+static void *irmc_connect(struct obex_session *os, int *err)
+{
+ struct irmc_session *irmc;
+ struct apparam_field *param;
+
+ DBG("");
+
+ manager_register_session(os);
+
+ irmc = g_new0(struct irmc_session, 1);
+ irmc->os = os;
+
+ /*
+ * FIXME:
+ * Ideally get capabilities info here and use that to define
+ * IrMC DID and SN etc parameters.
+ * For now lets used hostname and some 'random' value
+ */
+ gethostname(irmc->did, DID_LEN);
+ strncpy(irmc->sn, "12345", DID_LEN);
+ strncpy(irmc->manu, "obex", DID_LEN);
+ strncpy(irmc->model, "mymodel", DID_LEN);
+
+ /*
+ * We need to know the number of contact/cal/nt entries
+ * somewhere so why not do it now.
+ */
+ param = g_new0(struct apparam_field, 1);
+ param->maxlistcount = 0; /* to count the number of vcards... */
+ param->filter = 0x200085; /* UID TEL N VERSION */
+ irmc->params = param;
+ phonebook_pull("telecom/pb.vcf", irmc->params, phonebook_size_result,
+ irmc);
+
+ if (err)
+ *err = 0;
+
+ return irmc;
+}
+
+static int irmc_get(struct obex_session *os, obex_object_t *obj,
+ gboolean *stream, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+ const char *type = obex_get_type(os);
+ const char *name = obex_get_name(os);
+ char *path;
+ int ret;
+
+ DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
+
+ path = g_strdup(name);
+ *stream = TRUE;
+
+ ret = obex_get_stream_start(os, path);
+
+ g_free(path);
+
+ return ret;
+}
+
+static void irmc_disconnect(struct obex_session *os, void *user_data)
+{
+ struct irmc_session *irmc = user_data;
+
+ DBG("");
+
+ manager_unregister_session(os);
+
+ if (irmc->params) {
+ if (irmc->params->searchval)
+ g_free(irmc->params->searchval);
+ g_free(irmc->params);
+ }
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ g_free(irmc);
+}
+
+static int irmc_chkput(struct obex_session *os, void *user_data)
+{
+ DBG("");
+ /* Reject all PUTs */
+ return -EBADR;
+}
+
+static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+{
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ g_string_append_printf(irmc->buffer,
+ "MANU:%s\r\n"
+ "MOD:%s\r\n"
+ "SN:%s\r\n"
+ "IRMC-VERSION:1.1\r\n"
+ "PB-TYPE-TX:VCARD2.1\r\n"
+ "PB-TYPE-RX:NONE\r\n"
+ "CAL-TYPE-TX:NONE\r\n"
+ "CAL-TYPE-RX:NONE\r\n"
+ "MSG-TYPE-TX:NONE\r\n"
+ "MSG-TYPE-RX:NONE\r\n"
+ "NOTE-TYPE-TX:NONE\r\n"
+ "NOTE-TYPE-RX:NONE\r\n",
+ irmc->manu, irmc->model, irmc->sn);
+
+ return irmc;
+}
+
+static void *irmc_open_pb(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ GString *mybuf;
+ int ret;
+
+ if (!g_strcmp0(name, ".vcf")) {
+ /* how can we tell if the vcard count call already finished? */
+ ret = phonebook_pull("telecom/pb.vcf", irmc->params,
+ query_result, irmc);
+ if (ret < 0) {
+ DBG("phonebook_pull failed...");
+ goto fail;
+ }
+ return irmc;
+ }
+
+ if (!g_strcmp0(name, "/info.log")) {
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "IEL:2\r\n"
+ "DID:%s\r\n",
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount, irmc->did);
+ }
+ else if (!strncmp(name, "/luid/", 6)) {
+ name += 6;
+ if (!g_strcmp0(name, "cc.log")) {
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "%d\r\n", irmc->params->maxlistcount);
+ }
+ else {
+ int l = strlen(name);
+ /* FIXME:
+ * Reply the same to any *.log so we hopefully force a
+ * full phonebook dump.
+ * Is IEL:2 ok?
+ */
+ if (l > 4 && !g_strcmp0(name + l - 4, ".log")) {
+ DBG("changelog request, force whole book");
+ mybuf = g_string_new("");
+ g_string_printf(mybuf, "SN:%s\r\n"
+ "DID:%s\r\n"
+ "Total-Records:%d\r\n"
+ "Maximum-Records:%d\r\n"
+ "*\r\n",
+ irmc->sn, irmc->did,
+ irmc->params->maxlistcount,
+ irmc->params->maxlistcount);
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+ }
+ }
+ else {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ if (!irmc->buffer)
+ irmc->buffer = mybuf;
+ else {
+ irmc->buffer = g_string_append(irmc->buffer, mybuf->str);
+ string_free(mybuf);
+ }
+
+ return irmc;
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static void *irmc_open_cal(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ /* no suport yet. Just return an empty buffer. cal.vcs */
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ return irmc;
+}
+
+static void *irmc_open_nt(const char *name,
+ struct irmc_session *irmc, int *err)
+{
+ /* no suport yet. Just return an empty buffer. nt.vnt */
+ DBG("unsupported, returning empty buffer");
+ if (!irmc->buffer)
+ irmc->buffer = g_string_new("");
+
+ return irmc;
+}
+
+static void *irmc_open(const char *name, int oflag, mode_t mode,
+ void *context, size_t *size, int *err)
+{
+ struct irmc_session *irmc = context;
+ int ret;
+ const char *p;
+
+ DBG("name %s context %p", name, context);
+ if (oflag != O_RDONLY) {
+ ret = -EPERM;
+ goto fail;
+ }
+ if (name == NULL || strncmp(name, "telecom/", 8) != 0) {
+ ret = -EBADR;
+ goto fail;
+ }
+
+ p = name + 8;
+ if (!g_strcmp0(p, "devinfo.txt"))
+ return irmc_open_devinfo(irmc, err);
+ else if (!strncmp(p, "pb", 2))
+ return irmc_open_pb(p+2, irmc, err);
+ else if (!strncmp(p, "cal", 3))
+ return irmc_open_cal(p+3, irmc, err);
+ else if (!strncmp(p, "nt", 2))
+ return irmc_open_nt(p+2, irmc, err);
+
+fail:
+ if (err)
+ *err = ret;
+
+ return NULL;
+}
+
+static int irmc_close(void *object)
+{
+ struct irmc_session *irmc = object;
+
+ DBG("");
+ if (irmc->buffer) {
+ string_free(irmc->buffer);
+ irmc->buffer = NULL;
+ }
+
+ return 0;
+}
+
+static ssize_t irmc_read(void *object, void *buf, size_t count, uint8_t *hi)
+{
+ struct irmc_session *irmc = object;
+ int len;
+
+ DBG("buffer %p count %d", irmc->buffer, count);
+ if (!irmc->buffer)
+ return -EAGAIN;
+
+ *hi = OBEX_HDR_BODY;
+ len = string_read(irmc->buffer, buf, count);
+ DBG("returning %d bytes", len);
+ return len;
+}
+
+static struct obex_mime_type_driver irmc_driver = {
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .open = irmc_open,
+ .close = irmc_close,
+ .read = irmc_read,
+};
+
+static struct obex_service_driver irmc = {
+ .name = "IRMC Sync server",
+ .service = OBEX_IRMC,
+ .channel = IRMC_CHANNEL,
+ .record = IRMC_RECORD,
+ .target = IRMC_TARGET,
+ .target_size = IRMC_TARGET_SIZE,
+ .connect = irmc_connect,
+ .get = irmc_get,
+ .disconnect = irmc_disconnect,
+ .chkput = irmc_chkput
+};
+
+static int irmc_init(void)
+{
+ int err;
+
+ DBG("");
+ err = phonebook_init();
+ if (err < 0)
+ goto fail_pb_init;
+
+ err = obex_mime_type_driver_register(&irmc_driver);
+ if (err < 0)
+ goto fail_mime_irmc;
+
+ err = obex_service_driver_register(&irmc);
+ if (err < 0)
+ goto fail_irmc_reg;
+
+ return 0;
+
+fail_irmc_reg:
+ obex_mime_type_driver_unregister(&irmc_driver);
+fail_mime_irmc:
+ phonebook_exit();
+fail_pb_init:
+ return err;
+}
+
+static void irmc_exit(void)
+{
+ DBG("");
+ obex_service_driver_unregister(&irmc);
+ obex_mime_type_driver_unregister(&irmc_driver);
+ phonebook_exit();
+}
+
+OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
diff --git a/src/main.c b/src/main.c
index 649acf9..ef894cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -80,6 +80,7 @@ static gboolean option_autoaccept = FALSE;
static gboolean option_opp = FALSE;
static gboolean option_ftp = FALSE;
static gboolean option_pbap = FALSE;
+static gboolean option_irmc = FALSE;
static gboolean option_pcsuite = FALSE;
static gboolean option_symlinks = FALSE;
static gboolean option_syncevolution = FALSE;
@@ -120,6 +121,8 @@ static GOptionEntry options[] = {
"Enable Phonebook Access server" },
{ "pcsuite", 's', 0, G_OPTION_ARG_NONE, &option_pcsuite,
"Enable PC Suite Services server" },
+ { "irmc", 'i', 0, G_OPTION_ARG_NONE, &option_irmc,
+ "Enable IrMCSync server" },
{ "syncevolution", 'e', 0, G_OPTION_ARG_NONE, &option_syncevolution,
"Enable OBEX server for SyncEvolution" },
{ NULL },
@@ -208,9 +211,10 @@ int main(int argc, char *argv[])
if (option_opp == FALSE && option_ftp == FALSE &&
option_pbap == FALSE &&
+ option_irmc == FALSE &&
option_syncevolution == FALSE) {
fprintf(stderr, "No server selected (use either "
- "--opp, --ftp, --pbap or --syncevolution)\n");
+ "--opp, --ftp, --pbap, --irmc or --syncevolution)\n");
exit(EXIT_FAILURE);
}
@@ -266,6 +270,10 @@ int main(int argc, char *argv[])
option_autoaccept, option_symlinks,
option_capability);
+ if (option_irmc == TRUE)
+ obex_server_init(OBEX_IRMC, NULL, TRUE, FALSE, FALSE,
+ option_capability);
+
if (option_syncevolution == TRUE)
obex_server_init(OBEX_SYNCEVOLUTION, NULL, TRUE, FALSE,
FALSE, NULL);
diff --git a/src/obex.h b/src/obex.h
index 9424b6b..35723ca 100644
--- a/src/obex.h
+++ b/src/obex.h
@@ -34,7 +34,8 @@
#define OBEX_BIP (1 << 3)
#define OBEX_PBAP (1 << 4)
#define OBEX_PCSUITE (1 << 5)
-#define OBEX_SYNCEVOLUTION (1 << 6)
+#define OBEX_IRMC (1 << 6)
+#define OBEX_SYNCEVOLUTION (1 << 7)
#define TARGET_SIZE 16
--
1.7.2
^ permalink raw reply related
* Re: QuiC AMP development
From: Peter Krystad @ 2010-08-12 19:53 UTC (permalink / raw)
To: sober song
Cc: Gustavo F. Padovan, Mat Martineau, Ron Shaffer, linux-bluetooth
In-Reply-To: <AANLkTiny5zM=1vEPyn6iE9cJqi0v_o_i12GOUg=n=Dc7@mail.gmail.com>
Hi Sober,
Be careful not to top-post on this mailing list.
> Hi Shaffer/Peter
>
> static inline int send_a2mp_cmd(struct amp_mgr *mgr, u8 ident, u8
> code, u16 len, void *data) {
> struct a2mp_cmd_hdr *hdr;
> int plen;
> u8 *buf;
>
> BT_DBG("ident %d code %d", ident, code);
> plen = sizeof(*hdr) + len;
> buf = kzalloc(plen, GFP_ATOMIC);
> if (!buf)
> return -ENOMEM;
> hdr = (struct a2mp_cmd_hdr *) buf;
> hdr->code = code;
> hdr->ident = ident;
> hdr->len = cpu_to_le16(len);
> buf += sizeof(*hdr);
> memcpy(buf, data, len);
> return send_a2mp(mgr->a2mp_sock, (u8 *) hdr, plen);
> }
>
> I see that here have a malloc, but i don't see free, doesn't it cause
> memleak?
>
Looks like it, thanks. As Mat and I explained to Kevin and Dan at the
mini-summit the git repo we posted is a snapshot of our development tree,
and was provided so interested parties could review our approach. As we
post patches to the mailing list your review will be much appreciated.
> Regards
> sober
>
>
>>> >
>>> >* Ron Shaffer <rshaffer@codeaurora.org> [2010-08-08 21:43:36 -0500]:
>>> >
>>> >>As requested in today's summit discussions, here's a link that can be
>>> >>used to inspect the code we've done to add AMP support on the latest
>>> >>next tree.
>>> >>
>>> >>https://www.codeaurora.org/gitweb/quic/bluetooth/?p=bluetooth-next-2.6.git;a=summary
>>> >>branch pk-upstream
>>> >
>>> >
Peter.
--
Peter Krystad
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
^ permalink raw reply
* Re: Question about phonebook_add_contact
From: Vinicius Gomes @ 2010-08-12 17:59 UTC (permalink / raw)
To: Radoslaw Jablonski; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <4C63F363.4000400@nokia.com>
Hi Radek,
On Thu, Aug 12, 2010 at 10:13 AM, Radoslaw Jablonski
<ext-jablonski.radoslaw@nokia.com> wrote:
>
> Hi!
> I've got question about this part of code from beginning
> phonebook_add_contact func:
>
> if ((contact->numbers == NULL && (contact->fullname == NULL ||
> contact->fullname[0] == '\0')))
> return;
>
> Is this checking really needed in that place? It is possible to have
> contacts data
> in phonebook that have all data except phone set (by example: email
> addresses,
> main address etc). In that condition when we want to pull target vcard
> entry, then
> empty string will be returned even if user send ATTRIBUTE_MASK to include
> all fields
> in the result.
>
That piece of code is a legacy from simpler times, when we supported
less types of contact information.
> I'm asking because I have problem with "0.vcf" vcard (this is responsible
> for personal
> information of device owner). This entry by default does not have any
> phone's data
> filled in address book but it is mandatory to put this in vcard-listing.
> Actually, I am forced to initialize contact->numbers list with empty number
> even if
> none of number is available to return correct result for "0.vcf."(in
> phonebook-tracker)...
>
> Can this 'contact->numbers' checking be removed from there or maybe other
> phonebooks
> rely on this behaviour?
>From what I know, the Tracker backend is the only thing that relies on
that, so I think that check could be removed with little to no
problem. In fact, as you are already dealing with the empty numbers
list case, the problem is already solved.
>
> BR,
> Radek
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"
> in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
Cheers,
--
Vinicius
^ permalink raw reply
* Re: [PATCH] IrMC sync server support
From: Marcel J.E. Mol @ 2010-08-12 15:39 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <20100812145703.GD7345@joshua.mesa.nl>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset*=utf-8''%E2%80%9Cus-ascii, Size: 2553 bytes --]
On Thu, Aug 12, 2010 at 04:57:03PM +0200, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Thu, Aug 12, 2010 at 3:12 PM, Marcel J.E. Mol <marcel@mesa.nl> wrote:
> > abstracting it made de irmc_open() more clean (e.g. no buffer fills in
> > irmc_open()) and more readable in my opinion.
> > The specs for devinfo.txt contain many more attributes but the currrent
> > set seems to be enough. In future this may need to be extended and
> > supporting scripts may be needed for getting the info. The current
> > values are actually not correct I think as the will be the same for any
> > device now... (hence the hint for using x-obex/capabilities in
> > irmc_connect().)
>
> It doesn't look like we can use x-obex/capabilities for this
> devinfo.txt, afaik they are not the same thing, thats why I suggested
> open it as any regular file so the platforms has some way to customize
> it. Executing scripts is always tricky since you have to depend on
> async io to suspend the request while the script is running and resume
> when finished. Of course if there is no file called devinfo.txt then
> we can think about a default value, what does the spec says in this
> regard, is devinfo.txt mandatory? If not then we can just fail as we
> do for x-obex/capabilities when not set.
I don;t know how diffenent capbilities is from the things devinfo.txt
needs. On the n900 the capabilities script seems to provide what is needed
for devinfo.txt so I was lead by that...
I'm not suere how mandatory devinfo.txt is. My carkit did ask for it but
when I returned some data to it it never asked again... It probably will
when I remove my phones configuration from the carkit.
I never checked the specs again for it as it all seems to work fine with
the code as it is now. It also works for other n900 owners so i did not
bother any more.
I think the code seems to be in a reasonable state to be usefull now so
that is why I released it here. There is probably lots of extra work to be
done to be fully specs complient. But by releasing it other people can jump
in and improve...
Thanks,
-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] IrMC sync server support
From: Luiz Augusto von Dentz @ 2010-08-12 14:57 UTC (permalink / raw)
To: Marcel J.E. Mol; +Cc: linux-bluetooth
In-Reply-To: <20100812121212.GA16738@joshua.mesa.nl>
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset*=utf-8''%E2%80%9Cus-ascii, Size: 1210 bytes --]
Hi Marcel,
On Thu, Aug 12, 2010 at 3:12 PM, Marcel J.E. Mol <marcel@mesa.nl> wrote:
> abstracting it made de irmc_open() more clean (e.g. no buffer fills in
> irmc_open()) and more readable in my opinion.
> The specs for devinfo.txt contain many more attributes but the currrent
> set seems to be enough. In future this may need to be extended and
> supporting scripts may be needed for getting the info. The current
> values are actually not correct I think as the will be the same for any
> device now... (hence the hint for using x-obex/capabilities in
> irmc_connect().)
It doesn't look like we can use x-obex/capabilities for this
devinfo.txt, afaik they are not the same thing, thats why I suggested
open it as any regular file so the platforms has some way to customize
it. Executing scripts is always tricky since you have to depend on
async io to suspend the request while the script is running and resume
when finished. Of course if there is no file called devinfo.txt then
we can think about a default value, what does the spec says in this
regard, is devinfo.txt mandatory? If not then we can just fail as we
do for x-obex/capabilities when not set.
--
Luiz Augusto von Dentz
Computer Engineer
^ 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