@@ -42,6 +42,8 @@ struct vhci_data {
4242
4343 bool suspended ;
4444 bool wakeup ;
45+ __u16 msft_opcode ;
46+ bool aosp_capable ;
4547};
4648
4749static int vhci_open_dev (struct hci_dev * hdev )
@@ -194,6 +196,88 @@ static const struct file_operations force_wakeup_fops = {
194196 .llseek = default_llseek ,
195197};
196198
199+ static int msft_opcode_set (void * data , u64 val )
200+ {
201+ struct vhci_data * vhci = data ;
202+
203+ if (val > 0xffff || (val & 0xffff >> 10 ) != 0x3f )
204+ return - EINVAL ;
205+
206+ if (vhci -> msft_opcode )
207+ return - EALREADY ;
208+
209+ vhci -> msft_opcode = val ;
210+
211+ return 0 ;
212+ }
213+
214+ static int msft_opcode_get (void * data , u64 * val )
215+ {
216+ struct vhci_data * vhci = data ;
217+
218+ * val = vhci -> msft_opcode ;
219+
220+ return 0 ;
221+ }
222+
223+ DEFINE_DEBUGFS_ATTRIBUTE (msft_opcode_fops , msft_opcode_get , msft_opcode_set ,
224+ "%llu\n" );
225+
226+ static ssize_t aosp_capable_read (struct file * file , char __user * user_buf ,
227+ size_t count , loff_t * ppos )
228+ {
229+ struct vhci_data * vhci = file -> private_data ;
230+ char buf [3 ];
231+
232+ buf [0 ] = vhci -> aosp_capable ? 'Y' : 'N' ;
233+ buf [1 ] = '\n' ;
234+ buf [2 ] = '\0' ;
235+ return simple_read_from_buffer (user_buf , count , ppos , buf , 2 );
236+ }
237+
238+ static ssize_t aosp_capable_write (struct file * file ,
239+ const char __user * user_buf , size_t count ,
240+ loff_t * ppos )
241+ {
242+ struct vhci_data * vhci = file -> private_data ;
243+ bool enable ;
244+ int err ;
245+
246+ err = kstrtobool_from_user (user_buf , count , & enable );
247+ if (err )
248+ return err ;
249+
250+ if (!enable )
251+ return - EINVAL ;
252+
253+ if (vhci -> aosp_capable )
254+ return - EALREADY ;
255+
256+ vhci -> aosp_capable = enable ;
257+
258+ return count ;
259+ }
260+
261+ static const struct file_operations aosp_capable_fops = {
262+ .open = simple_open ,
263+ .read = aosp_capable_read ,
264+ .write = aosp_capable_write ,
265+ .llseek = default_llseek ,
266+ };
267+
268+ static int vhci_setup (struct hci_dev * hdev )
269+ {
270+ struct vhci_data * vhci = hci_get_drvdata (hdev );
271+
272+ if (vhci -> msft_opcode )
273+ hci_set_msft_opcode (hdev , vhci -> msft_opcode );
274+
275+ if (vhci -> aosp_capable )
276+ hci_set_aosp_capable (hdev );
277+
278+ return 0 ;
279+ }
280+
197281static int __vhci_create_device (struct vhci_data * data , __u8 opcode )
198282{
199283 struct hci_dev * hdev ;
@@ -236,6 +320,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
236320 hdev -> get_data_path_id = vhci_get_data_path_id ;
237321 hdev -> get_codec_config_data = vhci_get_codec_config_data ;
238322 hdev -> wakeup = vhci_wakeup ;
323+ hdev -> setup = vhci_setup ;
324+ set_bit (HCI_QUIRK_NON_PERSISTENT_SETUP , & hdev -> quirks );
239325
240326 /* bit 6 is for external configuration */
241327 if (opcode & 0x40 )
@@ -259,6 +345,14 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
259345 debugfs_create_file ("force_wakeup" , 0644 , hdev -> debugfs , data ,
260346 & force_wakeup_fops );
261347
348+ if (IS_ENABLED (CONFIG_BT_MSFTEXT ))
349+ debugfs_create_file ("msft_opcode" , 0644 , hdev -> debugfs , data ,
350+ & msft_opcode_fops );
351+
352+ if (IS_ENABLED (CONFIG_BT_AOSPEXT ))
353+ debugfs_create_file ("aosp_capable" , 0644 , hdev -> debugfs , data ,
354+ & aosp_capable_fops );
355+
262356 hci_skb_pkt_type (skb ) = HCI_VENDOR_PKT ;
263357
264358 skb_put_u8 (skb , 0xff );
0 commit comments