1 // SPDX-License-Identifier: LGPL-2.1-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2011-2014 Intel Corporation
7 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
27 #include "lib/bluetooth.h"
30 #include "src/shared/io.h"
31 #include "monitor/bt.h"
35 #define DEBUGFS_PATH "/sys/kernel/debug/bluetooth"
36 #define DEVCORE_PATH "/sys/class/devcoredump"
45 static void vhci_destroy(void *user_data)
47 struct vhci *vhci = user_data;
49 btdev_destroy(vhci->btdev);
55 static void vhci_write_callback(const struct iovec *iov, int iovlen,
58 struct vhci *vhci = user_data;
61 written = io_send(vhci->io, iov, iovlen);
66 static bool vhci_read_callback(struct io *io, void *user_data)
68 struct vhci *vhci = user_data;
69 int fd = io_get_fd(vhci->io);
70 unsigned char buf[4096];
73 len = read(fd, buf, sizeof(buf));
82 btdev_receive_h4(vhci->btdev, buf, len);
89 bool vhci_set_debug(struct vhci *vhci, vhci_debug_func_t callback,
90 void *user_data, vhci_destroy_func_t destroy)
95 return btdev_set_debug(vhci->btdev, callback, user_data, destroy);
98 struct vhci_create_req {
101 } __attribute__((packed));
103 struct vhci_create_rsp {
107 } __attribute__((packed));
109 struct vhci *vhci_open(uint8_t type)
112 struct vhci_create_req req;
113 struct vhci_create_rsp rsp;
116 fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
120 memset(&req, 0, sizeof(req));
121 req.pkt_type = HCI_VENDOR_PKT;
125 req.opcode = HCI_AMP;
128 req.opcode = HCI_PRIMARY;
132 if (write(fd, &req, sizeof(req)) < 0) {
137 memset(&rsp, 0, sizeof(rsp));
139 if (read(fd, &rsp, sizeof(rsp)) < 0) {
144 vhci = malloc(sizeof(*vhci));
150 memset(vhci, 0, sizeof(*vhci));
152 vhci->index = rsp.index;
153 vhci->io = io_new(fd);
155 io_set_close_on_destroy(vhci->io, true);
157 vhci->btdev = btdev_create(type, rsp.index);
163 btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci);
165 if (!io_set_read_handler(vhci->io, vhci_read_callback, vhci, NULL)) {
173 void vhci_close(struct vhci *vhci)
181 bool vhci_pause_input(struct vhci *vhci, bool paused)
184 return io_set_read_handler(vhci->io, NULL, NULL, NULL);
186 return io_set_read_handler(vhci->io, vhci_read_callback, vhci,
190 struct btdev *vhci_get_btdev(struct vhci *vhci)
198 static int vhci_debugfs_write(struct vhci *vhci, char *option, const void *data,
208 memset(path, 0, sizeof(path));
209 sprintf(path, DEBUGFS_PATH "/hci%d/%s", vhci->index, option);
211 fd = open(path, O_RDWR);
215 n = write(fd, data, len);
226 int vhci_set_force_suspend(struct vhci *vhci, bool enable)
230 val = (enable) ? 'Y' : 'N';
232 return vhci_debugfs_write(vhci, "force_suspend", &val, sizeof(val));
235 int vhci_set_force_wakeup(struct vhci *vhci, bool enable)
239 val = (enable) ? 'Y' : 'N';
241 return vhci_debugfs_write(vhci, "force_wakeup", &val, sizeof(val));
244 int vhci_set_msft_opcode(struct vhci *vhci, uint16_t opcode)
249 snprintf(val, sizeof(val), "0x%4x", opcode);
251 err = vhci_debugfs_write(vhci, "msft_opcode", &val, sizeof(val));
255 return btdev_set_msft_opcode(vhci->btdev, opcode);
258 int vhci_set_aosp_capable(struct vhci *vhci, bool enable)
262 val = (enable) ? 'Y' : 'N';
264 return vhci_debugfs_write(vhci, "aosp_capable", &val, sizeof(val));
267 int vhci_set_emu_opcode(struct vhci *vhci, uint16_t opcode)
269 return btdev_set_emu_opcode(vhci->btdev, opcode);
272 int vhci_set_force_static_address(struct vhci *vhci, bool enable)
276 val = (enable) ? 'Y' : 'N';
278 return vhci_debugfs_write(vhci, "force_static_address", &val,
282 int vhci_force_devcd(struct vhci *vhci, const void *data, size_t len)
284 return vhci_debugfs_write(vhci, "force_devcoredump", data, len);
287 int vhci_read_devcd(struct vhci *vhci, void *buf, size_t size)
290 struct dirent *entry;
291 char filename[PATH_MAX];
295 dir = opendir(DEVCORE_PATH);
299 while ((entry = readdir(dir)) != NULL) {
300 if (strstr(entry->d_name, "devcd"))
309 sprintf(filename, DEVCORE_PATH "/%s/data", entry->d_name);
310 fd = open(filename, O_RDWR);
316 ret = read(fd, buf, size);
322 /* Once the devcoredump is read, write anything to it to mark it for
325 if (write(fd, "0", 1) < 0) {