Bluetooth: Allow setting of codec for HFP offload use case
authorKiran K <kiran.k@intel.com>
Tue, 7 Sep 2021 10:12:42 +0000 (15:42 +0530)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Tue, 7 Sep 2021 21:09:18 +0000 (14:09 -0700)
This patch allows user space to set the codec that needs to
be used for HFP offload use case. The codec details are cached and
the controller is configured before opening the SCO connection.

Signed-off-by: Kiran K <kiran.k@intel.com>
Reviewed-by: Chethan T N <chethan.tumkur.narayan@intel.com>
Reviewed-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
include/net/bluetooth/bluetooth.h
net/bluetooth/sco.c

index 64cddff..536cae9 100644 (file)
@@ -173,6 +173,8 @@ struct bt_codecs {
        struct bt_codec codecs[];
 } __packed;
 
+#define BT_CODEC_CVSD  0x02
+
 __printf(1, 2)
 void bt_info(const char *fmt, ...);
 __printf(1, 2)
index df8cba0..aaf89c4 100644 (file)
@@ -69,6 +69,7 @@ struct sco_pinfo {
        __u32           flags;
        __u16           setting;
        __u8            cmsg_mask;
+       struct bt_codec codec;
        struct sco_conn *conn;
 };
 
@@ -441,6 +442,7 @@ static void __sco_sock_close(struct sock *sk)
                sock_set_flag(sk, SOCK_ZAPPED);
                break;
        }
+
 }
 
 /* Must be called on unlocked socket. */
@@ -501,6 +503,10 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
        sk->sk_state    = BT_OPEN;
 
        sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
+       sco_pi(sk)->codec.id = BT_CODEC_CVSD;
+       sco_pi(sk)->codec.cid = 0xffff;
+       sco_pi(sk)->codec.vid = 0xffff;
+       sco_pi(sk)->codec.data_path = 0x00;
 
        bt_sock_link(&sco_sk_list, sk);
        return sk;
@@ -833,6 +839,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
        int len, err = 0;
        struct bt_voice voice;
        u32 opt;
+       struct bt_codecs *codecs;
+       struct hci_dev *hdev;
+       __u8 buffer[255];
 
        BT_DBG("sk %p", sk);
 
@@ -894,6 +903,57 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
                        sco_pi(sk)->cmsg_mask &= SCO_CMSG_PKT_STATUS;
                break;
 
+       case BT_CODEC:
+               if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
+                   sk->sk_state != BT_CONNECT2) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
+                                    BDADDR_BREDR);
+               if (!hdev) {
+                       err = -EBADFD;
+                       break;
+               }
+
+               if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
+                       hci_dev_put(hdev);
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               if (!hdev->get_data_path_id) {
+                       hci_dev_put(hdev);
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               if (optlen < sizeof(struct bt_codecs) ||
+                   optlen > sizeof(buffer)) {
+                       hci_dev_put(hdev);
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (copy_from_sockptr(buffer, optval, optlen)) {
+                       hci_dev_put(hdev);
+                       err = -EFAULT;
+                       break;
+               }
+
+               codecs = (void *)buffer;
+
+               if (codecs->num_codecs > 1) {
+                       hci_dev_put(hdev);
+                       err = -EINVAL;
+                       break;
+               }
+
+               sco_pi(sk)->codec = codecs->codecs[0];
+               hci_dev_put(hdev);
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;