diff options
-rw-r--r-- | include/net/bluetooth/bluetooth.h | 8 | ||||
-rw-r--r-- | include/net/bluetooth/sco.h | 1 | ||||
-rw-r--r-- | net/bluetooth/sco.c | 40 |
3 files changed, 48 insertions, 1 deletions
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 10eb9b389014..10d43d8c7037 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h | |||
@@ -107,6 +107,14 @@ struct bt_power { | |||
107 | */ | 107 | */ |
108 | #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 | 108 | #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 |
109 | 109 | ||
110 | #define BT_VOICE 11 | ||
111 | struct bt_voice { | ||
112 | __u16 setting; | ||
113 | }; | ||
114 | |||
115 | #define BT_VOICE_TRANSPARENT 0x0003 | ||
116 | #define BT_VOICE_CVSD_16BIT 0x0060 | ||
117 | |||
110 | __printf(1, 2) | 118 | __printf(1, 2) |
111 | int bt_info(const char *fmt, ...); | 119 | int bt_info(const char *fmt, ...); |
112 | __printf(1, 2) | 120 | __printf(1, 2) |
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 1e35c43657c8..e252a31ee6b6 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h | |||
@@ -73,6 +73,7 @@ struct sco_conn { | |||
73 | struct sco_pinfo { | 73 | struct sco_pinfo { |
74 | struct bt_sock bt; | 74 | struct bt_sock bt; |
75 | __u32 flags; | 75 | __u32 flags; |
76 | __u16 setting; | ||
76 | struct sco_conn *conn; | 77 | struct sco_conn *conn; |
77 | }; | 78 | }; |
78 | 79 | ||
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index acdca68806db..678747e2e389 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c | |||
@@ -416,6 +416,8 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro | |||
416 | sk->sk_protocol = proto; | 416 | sk->sk_protocol = proto; |
417 | sk->sk_state = BT_OPEN; | 417 | sk->sk_state = BT_OPEN; |
418 | 418 | ||
419 | sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT; | ||
420 | |||
419 | setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk); | 421 | setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk); |
420 | 422 | ||
421 | bt_sock_link(&sco_sk_list, sk); | 423 | bt_sock_link(&sco_sk_list, sk); |
@@ -709,7 +711,8 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
709 | static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) | 711 | static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) |
710 | { | 712 | { |
711 | struct sock *sk = sock->sk; | 713 | struct sock *sk = sock->sk; |
712 | int err = 0; | 714 | int len, err = 0; |
715 | struct bt_voice voice; | ||
713 | u32 opt; | 716 | u32 opt; |
714 | 717 | ||
715 | BT_DBG("sk %p", sk); | 718 | BT_DBG("sk %p", sk); |
@@ -735,6 +738,31 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char | |||
735 | clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); | 738 | clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); |
736 | break; | 739 | break; |
737 | 740 | ||
741 | case BT_VOICE: | ||
742 | if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && | ||
743 | sk->sk_state != BT_CONNECT2) { | ||
744 | err = -EINVAL; | ||
745 | break; | ||
746 | } | ||
747 | |||
748 | voice.setting = sco_pi(sk)->setting; | ||
749 | |||
750 | len = min_t(unsigned int, sizeof(voice), optlen); | ||
751 | if (copy_from_user((char *) &voice, optval, len)) { | ||
752 | err = -EFAULT; | ||
753 | break; | ||
754 | } | ||
755 | |||
756 | /* Explicitly check for these values */ | ||
757 | if (voice.setting != BT_VOICE_TRANSPARENT && | ||
758 | voice.setting != BT_VOICE_CVSD_16BIT) { | ||
759 | err = -EINVAL; | ||
760 | break; | ||
761 | } | ||
762 | |||
763 | sco_pi(sk)->setting = voice.setting; | ||
764 | break; | ||
765 | |||
738 | default: | 766 | default: |
739 | err = -ENOPROTOOPT; | 767 | err = -ENOPROTOOPT; |
740 | break; | 768 | break; |
@@ -808,6 +836,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char | |||
808 | { | 836 | { |
809 | struct sock *sk = sock->sk; | 837 | struct sock *sk = sock->sk; |
810 | int len, err = 0; | 838 | int len, err = 0; |
839 | struct bt_voice voice; | ||
811 | 840 | ||
812 | BT_DBG("sk %p", sk); | 841 | BT_DBG("sk %p", sk); |
813 | 842 | ||
@@ -833,6 +862,15 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char | |||
833 | 862 | ||
834 | break; | 863 | break; |
835 | 864 | ||
865 | case BT_VOICE: | ||
866 | voice.setting = sco_pi(sk)->setting; | ||
867 | |||
868 | len = min_t(unsigned int, len, sizeof(voice)); | ||
869 | if (copy_to_user(optval, (char *)&voice, len)) | ||
870 | err = -EFAULT; | ||
871 | |||
872 | break; | ||
873 | |||
836 | default: | 874 | default: |
837 | err = -ENOPROTOOPT; | 875 | err = -ENOPROTOOPT; |
838 | break; | 876 | break; |