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 64cddff0c9c44d6ee795a371b4d8c13abbe1b7ac..536cae9a8bd7488aef5dc677f105d2a51e4ecb6e 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 df8cba0c9cc40c57b926067fbe3ca7b0b312e5bc..aaf89c41113ac31fd596dbc38a305eb4834602d9 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;