Bluetooth Driver ==================== .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Topics in this section, * :ref:`Learnings in this section ` * :ref:`Terminology ` * :ref:`Version Info ` * :ref:`Architecure ` * :ref:`HW ` * :ref:`SW ` * :ref:`Applications & Libraries ` * :ref:`Kernel & Driver modules ` * :ref:`List of driver modules ` * :ref:`Use case ` * :ref:`Driver Development ` * :ref:`Custom build of driver modules ` * :ref:`Load custom built driver modules ` * :ref:`Init path ` * :ref:`Control path ` * :ref:`Data path ` * :ref:`Contexts ` * :ref:`Threads ` * :ref:`Timers ` * :ref:`Interrupts ` * :ref:`Data Structures ` * :ref:`FAQs ` * :ref:`Reference links ` .. _FreebsdDeviceDriver_bluetooth_driver_step1: .. tab-set:: .. tab-item:: Learnings in this section * In this section, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * Bluetooth driver .. _FreebsdDeviceDriver_bluetooth_driver_step2: .. tab-set:: .. tab-item:: Terminology .. csv-table:: :file: ./terminology_info.csv :widths: 20,20,60 .. _FreebsdDeviceDriver_bluetooth_driver_step3: .. tab-set:: .. tab-item:: Version Info =============================== ======================================= # Version =============================== ======================================= Freebsd 14.1.0 =============================== ======================================= .. _FreebsdDeviceDriver_bluetooth_driver_step4: .. tab-set:: .. tab-item:: Architecture .. tab-set:: .. tab-item:: BT Architecture .. image:: bt_architecture.png :alt: Diagram :width: 500 :height: 300 .. tab-set:: .. tab-item:: BT Headset: SW Modules at high level .. image:: bt_headset_sw_modules_at_high_level.png :alt: Diagram :width: 500 :height: 300 .. csv-table:: :file: ./kernel_modules_info.csv :widths: 20,80 .. csv-table:: :file: ./library_modules_info.csv :widths: 20,80 .. csv-table:: :file: ./commands_info.csv :widths: 20,80 .. _FreebsdDeviceDriver_bluetooth_driver_step5: .. tab-set:: .. tab-item:: HW .. csv-table:: :file: ./hardware_info.csv :widths: 30, 70 .. tab-set:: .. tab-item:: Chips Interconnect .. image:: chips_interconnect.png :alt: Diagram :width: 800 :height: 300 .. tab-set:: .. tab-item:: BT .. csv-table:: :file: ./bt_hardware_info.csv :widths: 50,50 .. tab-set:: .. tab-item:: USB Host Controller .. csv-table:: :file: ./usb_host_controller_info.csv :widths: 50,50 .. tab-set:: .. tab-item:: PCI Host Controller .. csv-table:: :file: ./pci_host_controller_info.csv :widths: 30,70 .. _FreebsdDeviceDriver_bluetooth_driver_step6: .. tab-set:: .. tab-item:: SW .. _FreebsdDeviceDriver_bluetooth_driver_step7: .. tab-set:: .. tab-item:: Applications & Libraries * Bluetooth setup script .. tab-set:: .. tab-item:: ngctl * Netgraph control utility. It creates a new netgraph node of type socket which can be used to issue netgraph commands .. csv-table:: :file: ./ngctl.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ngctl) --> (lib netgraph.so) (ngctl) --> (libthr.so.3) (ngctl) --> (libc.so.7) (ngctl) --> (libedit.so) (ngctl) --> (libtinfow.so.9) (lib netgraph.so) --> (libc.so.7) (libthr.so.3) --> (libc.so.7) (libedit.so) --> (libc.so.7) (libtinfow.so.9) --> (libc.so.7) @enduml .. csv-table:: :file: ./ngctl_dependency.csv :widths: 80 .. tab-set:: .. tab-item:: hcsecd * Daemon that controls link keys and PIN codes for Bluetooth devices .. csv-table:: :file: ./hcsecd.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (hcsecd) --> (libbluetooth.so.4) (hcsecd) --> (libc.so.7) (libbluetooth.so.4) -right-> (libc.so.7) @enduml .. csv-table:: :file: ./hcsecd_dependency.csv :widths: 80 .. tab-set:: .. tab-item:: hccontrol * Bluetooth HCI configuration utility .. csv-table:: :file: ./hccontrol.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (hccontrol) --> (libbluetooth.so.4) (hccontrol) --> (libc.so.7) (libbluetooth.so.4) -right-> (libc.so.7) @enduml .. csv-table:: :file: ./hccontrol_dependency.csv :widths: 80 .. tab-set:: .. tab-item:: usbconfig * Utility used to configure and dump information about the USB subsystem .. csv-table:: :file: ./usbconfig.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (usbconfig) --> (libusb.so.3) (usbconfig) --> (libthr.so.3) (libusb.so.3) -right-> (libthr.so.3) (libusb.so.3) --> (libc.so.7) (libthr.so.3) --> (libc.so.7) (usbconfig) --> (libc.so.7) @enduml .. csv-table:: :file: ./usbconfig_dependency.csv :widths: 80 .. tab-set:: .. tab-item:: virtual_oss * Audio mixing application that multiplexes and demultiplexes a single OSS device into multiple customizable OSS compatible devices using character devices from userspace .. csv-table:: :file: ./virtual_oss.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (virtual_oss) -right-> (libsamplerate.so.0) (virtual_oss) -left-> (libbluetooth.so.4) (virtual_oss) --> (libnv.so.1) (virtual_oss) --> (libsdp.so.4) (virtual_oss) --> (libcuse.so.1) (virtual_oss) --> (libthr.so.3) (virtual_oss) --> (libfftw3.so.3) (virtual_oss) --> (libm.so.5) (libsamplerate.so.0) --> (libm.so.5) (virtual_oss) --> (libc.so.7) (libcuse.so.1) --> (libthr.so.3) (libfftw3.so.3) --> (libm.so.5) (libsdp.so.4) --> (libc.so.7) (libcuse.so.1) --> (libc.so.7) (libm.so.5) --> (libc.so.7) (libthr.so.3) --> (libc.so.7) (libnv.so.1) --> (libc.so.7) (libbluetooth.so.4) --> (libc.so.7) (libfftw3.so.3) --> (libc.so.7) (libsamplerate.so.0) -> (libc.so.7) @enduml .. csv-table:: :file: ./virtual_oss_dependency.csv :widths: 80 .. _FreebsdDeviceDriver_bluetooth_driver_step8: .. tab-set:: .. tab-item:: Kernel & Driver modules .. _FreebsdDeviceDriver_bluetooth_driver_step9: .. tab-set:: .. tab-item:: List of driver modules .. tab-set:: .. tab-item:: 1. ng_ubt.ko * Driver for Bluetooth USB devices .. csv-table:: :file: ./ng_ubt_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ng_ubt.ko) --> (netgraph.ko) (netgraph.ko) --> (kernel) (ng_ubt.ko) --> (ng_bluetooth.ko) (ng_ubt.ko) --> (usb.ko) (ng_ubt.ko) --> (kernel) (ng_bluetooth.ko) --> (kernel) (usb.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 2. netgraph.ko * The netgraph system provides a uniform and modular system for the implementation of kernel objects which perform various networking function .. csv-table:: :file: ./netgraph_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (netgraph.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 3. ng_hci.ko * Bluetooth Host Controller Interface (HCI) layer .. csv-table:: :file: ./ng_hci_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ng_hci.ko) --> (netgraph.ko) (ng_hci.ko) --> (kernel) (ng_hci.ko) --> (ng_bluetooth.ko) (netgraph.ko) --> (kernel) (ng_bluetooth.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 4. ng_bluetooth.ko * Placeholder for global Bluetooth variables .. csv-table:: :file: ./ng_bluetooth_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ng_bluetooth.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 5. ng_btsocket.ko * Bluetooth sockets layer. The ng_btsocket module implements three Netgraph node types. Each type in its turn implements one protocol within PF_BLUETOOTH domain. .. csv-table:: :file: ./ng_btsocket.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ng_btsocket.ko) --> (netgraph.ko) (ng_btsocket.ko) --> (kernel) (ng_btsocket.ko) --> (ng_bluetooth.ko) (netgraph.ko) --> (kernel) (ng_bluetooth.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 6. ng_l2cap.ko * Bluetooth Logical Link Control and Adaptation Protocol (L2CAP) .. csv-table:: :file: ./ng_l2cap.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (ng_l2cap.ko) --> (netgraph.ko) (ng_l2cap.ko) --> (kernel) (ng_l2cap.ko) --> (ng_bluetooth.ko) (netgraph.ko) --> (kernel) (ng_bluetooth.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 7. usb.ko * Interfaces for directly managing a usb device .. csv-table:: :file: ./usb.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (usb.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 8. xhci.ko * USB extensible host controller driver .. csv-table:: :file: ./xhci_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (xhci.ko) --> (usb.ko) (xhci.ko) --> (kernel) (usb.ko) -right-> (kernel) @enduml .. tab-set:: .. tab-item:: 8. sound.ko * FreeBSD PCM audio device infrastructure * The sound drivers may create the following device nodes: * 1. /dev/dsp%d: Audio device. The number represents the unit number of the device. * 2. /dev/dsp: Alias of /dev/dsp${hw.snd.default_unit}. Available only if hw.snd.basename_clone is set. * 3. /dev/sndstat: Current sound status, including all channels and drivers * sndstat : nvlist-based PCM audio device enumeration interface. The ioctl interface provided by /dev/sndstat device allows callers to enumerate PCM audio devices available for use. .. csv-table:: :file: ./sound_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (sound.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 9. snd_hda.ko * Intel High Definition Audio bridge device driver .. csv-table:: :file: ./snd_hda_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (snd_hda.ko) --> (sound.ko) (snd_hda.ko) --> (kernel) @enduml .. tab-set:: .. tab-item:: 10. cuse.ko * Userland character device driver .. csv-table:: :file: ./cuse_ko.csv :widths: 50, 50 .. tab-set:: .. tab-item:: Dependencies .. plantuml:: @startuml (cuse.ko) --> (kernel) @enduml .. _FreebsdDeviceDriver_bluetooth_driver_step10: .. tab-set:: .. tab-item:: Use case .. tab-set:: .. tab-item:: 1. Check if your FreeBSD laptop has an Intel Bluetooth chipset .. code-block:: shell test:~$ usbconfig ugen0.1: at usbus0, cfg=0 md=HOST spd=SUPER (5.0Gbps) pwr=SAVE (0mA) ugen0.2: at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (500mA) ugen0.3: at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (100mA) ugen0.4: at usbus0, cfg=0 md=HOST spd=FULL (12Mbps) pwr=ON (100mA) * From above output we know ‘Wireless-AC 3168 Bluetooth Intel Corp’ chip and ‘Intel XHCI root HUB’ is used .. tab-set:: .. tab-item:: 2. Install the Intel BT firmware binary, iwmbt-firmware .. code-block:: c test:~$ pkg install iwmbt-firmware .. tab-set:: .. tab-item:: 3. After installing the firmware, reboot or restart ‘devd’ to enable it .. code-block:: c test:~$ service devd restart .. tab-set:: .. tab-item:: 4. Install Virtual OSS which is required for Bluetooth audio to work on FreeBSD .. code-block:: c test:~$ pkg install virtual_oss .. tab-set:: .. tab-item:: 5. Virtual OSS requires the user space character device driver (CUSE) to be loaded. * Load it manually and enable loading for every boot .. code-block:: c test:~$ kldload cuse test:~$ sysrc kld_list+="cuse" .. tab-set:: .. tab-item:: 6. Start Bluetooth Stack .. code-block:: c test:~$ service hcsecd onestart * If this fails, do it again .. code-block:: c test:~$ service bluetooth start ubt0 * If Bluetooth is started successfully, below logs should be seen in dmesg .. code-block:: c test:~$ dmesg | grep ubt0 ubt0 on uhub0 ubt0: on usbus0 * Output of ngctl .. code-block:: c test:~$ ngctl list There are 8 total nodes: Name: ubt0 Type: ubt ID: 00000001 Num hooks: 1 Name: btsock_l2c Type: btsock_l2c ID: 00000002 Num hooks: 1 Name: ubt0hci Type: hci ID: 00000023 Num hooks: 3 Name: btsock_l2c_raw Type: btsock_l2c_raw ID: 00000003 Num hooks: 1 Name: btsock_hci_raw Type: btsock_hci_raw ID: 00000004 Num hooks: 1 Name: btsock_sco Type: btsock_sco ID: 00000005 Num hooks: 0 Name: ubt0l2cap Type: l2cap ID: 00000027 Num hooks: 3 Name: ngctl3789 Type: socket ID: 0000002d Num hooks: 0 .. tab-set:: .. tab-item:: 7. Find your Bluetooth headphones (put your headphones in pairing mode) .. code-block:: shell test:~$ hccontrol -n ubt0hci inquiry Inquiry result, num_responses=1 Inquiry result #0 BD_ADDR: f8:9e:94:ee:99:c3 Page Scan Rep. Mode: 0x1 Page Scan Period Mode: 00 Page Scan Mode: 00 Class: 2a:01:0c Clock offset: 0x333b Inquiry complete. Status: No error [00] .. tab-set:: .. tab-item:: 8. Find out the name assigned to Bluetooth device to check if the scanned device is Bluetooth headphone .. code-block:: c test:~$ hccontrol -n ubt0hci remote_name_request f8:9e:94:ee:99:c3 BD_ADDR: f8:9e:94:ee:99:c3 Name: OnePlus Buds .. tab-set:: .. tab-item:: 9. Edit ‘/etc/bluetooth/hcsecd.conf’ and add your Bluetooth device * Headphones does not require a key or pin so I add nokey and 0000 as the pin .. code-block:: c test:~$ vim /etc/bluetooth/hcsecd.conf device { bdaddr f8:9e:94:ee:99:c3; name "OnePlus Buds"; key nokey; pin "0000"; } .. tab-set:: .. tab-item:: 10. Edit ‘/etc/bluetooth/hosts’ to assign an alias to your Bluetooth device * This step is optional, ‘/etc/bluetooth/hosts’ allows you to alias BD_ADDR addresses to names making it much easier to remember .. code-block:: c test:~$ vim /etc/bluetooth/hosts f8:9e:94:ee:99:c3 headphones .. tab-set:: .. tab-item:: 11. Create connection to your Bluetooth headphones (Make sure headphones are in pairing mode) .. code-block:: c test:~$ hccontrol -n ubt0hci create_connection headphones * Note:  Enable “write_authentication” on the HCI node, if you observe below error * Error message: .. code-block:: c test:~$ hccontrol -n ubt0hci create_connection headphones BD_ADDR: headphones Connection handle: 256 Encryption mode: Disabled [0] * Resolution: .. code-block:: c test:~$ hccontrol -n ubt0hci write_authentication_enable 1 test:~$ hccontrol -n ubt0hci create_connection headphones .. tab-set:: .. tab-item:: 12. Check if headphones are connected .. code-block:: c test:~$ hccontrol -n ubt0hci read_connection_list Remote BD_ADDR Handle Type Mode Role Encrypt Pending Queue State headphones 256 ACL 0 MAST NONE 0 0 OPEN .. tab-set:: .. tab-item:: 13. Create a virtual sound device so you can use your bluetooth headphones as a sound sink * Meaning of the below command: * To expose virtual device to other apps, install entry in /dev/sndstat. (-T /dev/sndstat) * Enabled automatic resampling to fix bad sound quality when playing audio with a different sample-rate than default. (-S) * If the default volume is too high, set a negative output amplification. (-a o,-4) * Sample rate of 44100 Hz is chosen, you can use 48000 Hz instead if that's better for your hardware. (-r 44100) * To use laptop's internal mic simultaneously while using my headphones. ( -R /dev/dsp0). You can disable the recording device by setting "-R /dev/null" instead. .. code-block:: c test:~$ virtual_oss -T /dev/sndstat -S -a o,-4 -C 2 -c 2 -r 44100 -b 16 -s 1024 -R /dev/dsp0 -P /dev/bluetooth/headphones -d dsp -t vdsp.ctl * Now we should have another DSP device listed in /dev/sndstat .. code-block:: c test:~$ cat /dev/sndstat Installed devices: pcm0: (play/rec) default pcm1: (rec) pcm2: (play) Installed devices from userspace: dsp: (play/rec) * Above steps works great for programs that use OSS as sound backend. However, other backends need additional steps .. tab-set:: .. tab-item:: 14. To fix applications that use sndio as backend (e.g. Chromium), enable the sndiod service .. code-block:: c test:~$ sysrc sndiod_enable=YES test:~$ service sndiod start .. tab-set:: .. tab-item:: 15. To fix applications that use a pulseaudio as backend (e.g. Firefox and linux Brave) * Method-1: Configure firefox to use OSS instead of pulseaudio * Open up firefox and put about:config in the URL line * Then add the following entry * media.cubeb.backend: oss * Method-2: Redirect all OSS output into pulseaudio. It adds latency to the audio but works .. code-block:: c test:~$ pacat --record -d oss_output.dsp0.monitor .. _FreebsdDeviceDriver_bluetooth_driver_step11: .. tab-set:: .. tab-item:: Driver Development .. _FreebsdDeviceDriver_bluetooth_driver_step12: .. tab-set:: .. tab-item:: Custom build of driver modules .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step13: .. tab-set:: .. tab-item:: Load custom built driver modules .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step14: .. tab-set:: .. tab-item:: Init path .. tab-set:: .. tab-item:: Device structure * Abstract representation of a device * Defined in /usr/src/stand/kshim/bsd_kernel.h .. code-block:: c typedef struct device *device_t; struct device { TAILQ_HEAD(device_list, device) dev_children; TAILQ_ENTRY(device) dev_link; struct device *dev_parent; const struct module_data *dev_module; void *dev_sc; void *dev_aux; driver_filter_t *dev_irq_filter; driver_intr_t *dev_irq_fn; void *dev_irq_arg; uint16_t dev_unit; char dev_nameunit[64]; char dev_desc[64]; uint8_t dev_res_alloc:1; uint8_t dev_quiet:1; uint8_t dev_softc_set:1; uint8_t dev_softc_alloc:1; uint8_t dev_attached:1; uint8_t dev_fixed_class:1; uint8_t dev_unit_manual:1; }; * The device object represents a piece of hardware attached to the system. * Ex: expansion card, the bus which that card is plugged into, disk drives attached to the expansion card, … * The system defines one device, - root_bus. * All other devices are created dynamically during auto configuration. * device_probe_and_attach() * initialise a device * This function is called during autoconfiguration to initialise the devices in the system. * For each device, the DEVICE_PROBE method of each suitable driver is called and if a probe succeeds, a description of the device is printed and the DEVICE_ATTACH method is called * DEVICE_PROBE * probe for device existence * method should probe to see if the device is present. * DEVICE_ATTACH * attach a device * Attach a device to the system after the DEVICE_PROBE() method has been called and has indicated that the device exists .. tab-set:: .. tab-item:: Driver structure * structure describing a device driver * Defined in /usr/src/stand/kshim/bsd_kernel.h .. code-block:: c typedef struct driver driver_t; struct driver { const char * name; const struct device_method *methods; uint32_t size; }; * Driver is registered with the system by the DRIVER_MODULE macro * Each driver will implement one or more sets of methods called interfaces. * Ex: methods from Device interface, methods from Bus interface .. tab-set:: .. tab-item:: Communication * ng_ubt(BT driver/host controller) --> usb.ko(USB client driver) --> xhci.ko(USB host controller) --> pci(client driver) --> pci host controller .. tab-set:: .. tab-item:: Init Path .. code-block:: c device_probe_and_attach() device_probe() pci_probe() // pci controller xhci_probe() // USB host controller uhub_probe() // hub connected to usb ubt_probe() // USB Bluetooth device device_attach() pci_attach() // pci controller xhci_attach() // USB host controller ubt_attach() // // USB Bluetooth device uhub_attach() // hub connected to usb uhub_explore_sub() usb_probe_and_attach() .. _FreebsdDeviceDriver_bluetooth_driver_step15: .. tab-set:: .. tab-item:: Control path .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step16: .. tab-set:: .. tab-item:: Data path .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step17: .. tab-set:: .. tab-item:: Contexts .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step18: .. tab-set:: .. tab-item:: Threads .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step19: .. tab-set:: .. tab-item:: Timers .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step20: .. tab-set:: .. tab-item:: Interrupts .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step21: .. tab-set:: .. tab-item:: Data Structures .. code-block:: c test:~$ .. _FreebsdDeviceDriver_bluetooth_driver_step22: .. tab-set:: .. tab-item:: FAQs * 1. Which codec? * 2. Which BT version? * 3. Which Freebsd version? * 4. Which BT profile is being used? HSP/HFP? * 5. Are you using AVRCP? * 6. Downloaded audio file is played? different audio file formats? * 7. File play to listening --- sw modules and HW modules involved(Including BT and Audio) * 8. Are we using BLE here? * 9. Frames exchanged for device pairing, unpair? can we confirm using prints Tx/Rx in application or driver? * 10. How is Reliability achieved? similar to Ack mechanism in wifi is reliablity maintainted at Application level(VLC media player/Youtube) or at BT level? * 11. The BT driver modules, are they native to FreeBSD or ported from Linux? .. _FreebsdDeviceDriver_bluetooth_driver_step23: .. tab-set:: .. tab-item:: Reference links * `Networking Basics: WiFi and Bluetooth `_ * `Configure Bluetooth Headphones on FreeBSD 13.1 `_ * `How to connect and use Bluetooth headphones on FreeBSD `_ * `Port details `_