Commit 2dea632f9acad076370fe871d4ccc93868621403

Authored by Frédéric Dalleau
Committed by Gustavo Padovan
1 parent 1a4c958cf9

Bluetooth: Add SCO connection fallback

When initiating a transparent eSCO connection, make use of T2 settings
at first try. T2 is the recommended settings from HFP 1.6 WideBand
Speech. Upon connection failure, try T1 settings.

When CVSD is requested and eSCO is supported, try to establish eSCO
connection using S3 settings. If it fails, fallback in sequence to S2,
S1, D1, D0 settings.

To know which setting should be used, conn->attempt is used. It
indicates the currently ongoing SCO connection attempt and can be used
as the index for the fallback settings table.

These setting and the fallback order are described in Bluetooth HFP 1.6
specification p. 101.

Signed-off-by: Frédéric Dalleau <frederic.dalleau@linux.intel.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>

Showing 3 changed files with 40 additions and 12 deletions Side-by-side Diff

include/net/bluetooth/hci_core.h
... ... @@ -570,7 +570,7 @@
570 570 }
571 571  
572 572 void hci_disconnect(struct hci_conn *conn, __u8 reason);
573   -void hci_setup_sync(struct hci_conn *conn, __u16 handle);
  573 +bool hci_setup_sync(struct hci_conn *conn, __u16 handle);
574 574 void hci_sco_setup(struct hci_conn *conn, __u8 status);
575 575  
576 576 struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
net/bluetooth/hci_conn.c
... ... @@ -31,6 +31,24 @@
31 31 #include <net/bluetooth/a2mp.h>
32 32 #include <net/bluetooth/smp.h>
33 33  
  34 +struct sco_param {
  35 + u16 pkt_type;
  36 + u16 max_latency;
  37 +};
  38 +
  39 +static const struct sco_param sco_param_cvsd[] = {
  40 + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */
  41 + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */
  42 + { EDR_ESCO_MASK | ESCO_EV3, 0x0007 }, /* S1 */
  43 + { EDR_ESCO_MASK | ESCO_HV3, 0xffff }, /* D1 */
  44 + { EDR_ESCO_MASK | ESCO_HV1, 0xffff }, /* D0 */
  45 +};
  46 +
  47 +static const struct sco_param sco_param_wideband[] = {
  48 + { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */
  49 + { EDR_ESCO_MASK | ESCO_EV3, 0x0008 }, /* T1 */
  50 +};
  51 +
34 52 static void hci_le_create_connection(struct hci_conn *conn)
35 53 {
36 54 struct hci_dev *hdev = conn->hdev;
37 55  
... ... @@ -172,10 +190,11 @@
172 190 hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
173 191 }
174 192  
175   -void hci_setup_sync(struct hci_conn *conn, __u16 handle)
  193 +bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
176 194 {
177 195 struct hci_dev *hdev = conn->hdev;
178 196 struct hci_cp_setup_sync_conn cp;
  197 + const struct sco_param *param;
179 198  
180 199 BT_DBG("hcon %p", conn);
181 200  
182 201  
183 202  
184 203  
185 204  
... ... @@ -192,19 +211,28 @@
192 211  
193 212 switch (conn->setting & SCO_AIRMODE_MASK) {
194 213 case SCO_AIRMODE_TRANSP:
195   - cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK &
196   - ~ESCO_2EV3);
197   - cp.max_latency = __constant_cpu_to_le16(0x000d);
  214 + if (conn->attempt > ARRAY_SIZE(sco_param_wideband))
  215 + return false;
198 216 cp.retrans_effort = 0x02;
  217 + param = &sco_param_wideband[conn->attempt - 1];
199 218 break;
200 219 case SCO_AIRMODE_CVSD:
201   - cp.pkt_type = cpu_to_le16(conn->pkt_type);
202   - cp.max_latency = __constant_cpu_to_le16(0xffff);
203   - cp.retrans_effort = 0xff;
  220 + if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
  221 + return false;
  222 + cp.retrans_effort = 0x01;
  223 + param = &sco_param_cvsd[conn->attempt - 1];
204 224 break;
  225 + default:
  226 + return false;
205 227 }
206 228  
207   - hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
  229 + cp.pkt_type = __cpu_to_le16(param->pkt_type);
  230 + cp.max_latency = __cpu_to_le16(param->max_latency);
  231 +
  232 + if (hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
  233 + return false;
  234 +
  235 + return true;
208 236 }
209 237  
210 238 void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
net/bluetooth/hci_event.c
... ... @@ -2909,11 +2909,11 @@
2909 2909 case 0x1c: /* SCO interval rejected */
2910 2910 case 0x1a: /* Unsupported Remote Feature */
2911 2911 case 0x1f: /* Unspecified error */
2912   - if (conn->out && conn->attempt < 2) {
  2912 + if (conn->out) {
2913 2913 conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
2914 2914 (hdev->esco_type & EDR_ESCO_MASK);
2915   - hci_setup_sync(conn, conn->link->handle);
2916   - goto unlock;
  2915 + if (hci_setup_sync(conn, conn->link->handle))
  2916 + goto unlock;
2917 2917 }
2918 2918 /* fall through */
2919 2919