forked from mirrors/linux
		
	Bluetooth: vhci: Add support for setting msft_opcode and aosp_capable
This adds a debugfs entries to set msft_opcode and aosp_capable enabling vhci to emulate controllers with MSFT/AOSP extension support. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
		
							parent
							
								
									60c6a63a3d
								
							
						
					
					
						commit
						b8f5482c96
					
				
					 1 changed files with 94 additions and 0 deletions
				
			
		| 
						 | 
					@ -42,6 +42,8 @@ struct vhci_data {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool suspended;
 | 
						bool suspended;
 | 
				
			||||||
	bool wakeup;
 | 
						bool wakeup;
 | 
				
			||||||
 | 
						__u16 msft_opcode;
 | 
				
			||||||
 | 
						bool aosp_capable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int vhci_open_dev(struct hci_dev *hdev)
 | 
					static int vhci_open_dev(struct hci_dev *hdev)
 | 
				
			||||||
| 
						 | 
					@ -194,6 +196,88 @@ static const struct file_operations force_wakeup_fops = {
 | 
				
			||||||
	.llseek		= default_llseek,
 | 
						.llseek		= default_llseek,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int msft_opcode_set(void *data, u64 val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vhci_data *vhci = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (val > 0xffff || (val & 0xffff >> 10) != 0x3f)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vhci->msft_opcode)
 | 
				
			||||||
 | 
							return -EALREADY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vhci->msft_opcode = val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int msft_opcode_get(void *data, u64 *val)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vhci_data *vhci = data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*val = vhci->msft_opcode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFINE_DEBUGFS_ATTRIBUTE(msft_opcode_fops, msft_opcode_get, msft_opcode_set,
 | 
				
			||||||
 | 
								 "%llu\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t aosp_capable_read(struct file *file, char __user *user_buf,
 | 
				
			||||||
 | 
									 size_t count, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vhci_data *vhci = file->private_data;
 | 
				
			||||||
 | 
						char buf[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						buf[0] = vhci->aosp_capable ? 'Y' : 'N';
 | 
				
			||||||
 | 
						buf[1] = '\n';
 | 
				
			||||||
 | 
						buf[2] = '\0';
 | 
				
			||||||
 | 
						return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t aosp_capable_write(struct file *file,
 | 
				
			||||||
 | 
									  const char __user *user_buf, size_t count,
 | 
				
			||||||
 | 
									  loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vhci_data *vhci = file->private_data;
 | 
				
			||||||
 | 
						bool enable;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = kstrtobool_from_user(user_buf, count, &enable);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!enable)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vhci->aosp_capable)
 | 
				
			||||||
 | 
							return -EALREADY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vhci->aosp_capable = enable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct file_operations aosp_capable_fops = {
 | 
				
			||||||
 | 
						.open		= simple_open,
 | 
				
			||||||
 | 
						.read		= aosp_capable_read,
 | 
				
			||||||
 | 
						.write		= aosp_capable_write,
 | 
				
			||||||
 | 
						.llseek		= default_llseek,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int vhci_setup(struct hci_dev *hdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vhci_data *vhci = hci_get_drvdata(hdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vhci->msft_opcode)
 | 
				
			||||||
 | 
							hci_set_msft_opcode(hdev, vhci->msft_opcode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (vhci->aosp_capable)
 | 
				
			||||||
 | 
							hci_set_aosp_capable(hdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 | 
					static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct hci_dev *hdev;
 | 
						struct hci_dev *hdev;
 | 
				
			||||||
| 
						 | 
					@ -236,6 +320,8 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 | 
				
			||||||
	hdev->get_data_path_id = vhci_get_data_path_id;
 | 
						hdev->get_data_path_id = vhci_get_data_path_id;
 | 
				
			||||||
	hdev->get_codec_config_data = vhci_get_codec_config_data;
 | 
						hdev->get_codec_config_data = vhci_get_codec_config_data;
 | 
				
			||||||
	hdev->wakeup = vhci_wakeup;
 | 
						hdev->wakeup = vhci_wakeup;
 | 
				
			||||||
 | 
						hdev->setup = vhci_setup;
 | 
				
			||||||
 | 
						set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* bit 6 is for external configuration */
 | 
						/* bit 6 is for external configuration */
 | 
				
			||||||
	if (opcode & 0x40)
 | 
						if (opcode & 0x40)
 | 
				
			||||||
| 
						 | 
					@ -259,6 +345,14 @@ static int __vhci_create_device(struct vhci_data *data, __u8 opcode)
 | 
				
			||||||
	debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
 | 
						debugfs_create_file("force_wakeup", 0644, hdev->debugfs, data,
 | 
				
			||||||
			    &force_wakeup_fops);
 | 
								    &force_wakeup_fops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_BT_MSFTEXT))
 | 
				
			||||||
 | 
							debugfs_create_file("msft_opcode", 0644, hdev->debugfs, data,
 | 
				
			||||||
 | 
									    &msft_opcode_fops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ENABLED(CONFIG_BT_AOSPEXT))
 | 
				
			||||||
 | 
							debugfs_create_file("aosp_capable", 0644, hdev->debugfs, data,
 | 
				
			||||||
 | 
									    &aosp_capable_fops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
 | 
						hci_skb_pkt_type(skb) = HCI_VENDOR_PKT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	skb_put_u8(skb, 0xff);
 | 
						skb_put_u8(skb, 0xff);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue