1*46757a3eSGeoffrey D. Bennett /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2*46757a3eSGeoffrey D. Bennett /* 3*46757a3eSGeoffrey D. Bennett * Focusrite Control Protocol Driver for ALSA 4*46757a3eSGeoffrey D. Bennett * 5*46757a3eSGeoffrey D. Bennett * Copyright (c) 2024-2025 by Geoffrey D. Bennett <g at b4.vu> 6*46757a3eSGeoffrey D. Bennett */ 7*46757a3eSGeoffrey D. Bennett /* 8*46757a3eSGeoffrey D. Bennett * DOC: FCP (Focusrite Control Protocol) User-Space API 9*46757a3eSGeoffrey D. Bennett * 10*46757a3eSGeoffrey D. Bennett * This header defines the interface between the FCP kernel driver and 11*46757a3eSGeoffrey D. Bennett * user-space programs to enable the use of the proprietary features 12*46757a3eSGeoffrey D. Bennett * available in Focusrite USB audio interfaces. This includes Scarlett 13*46757a3eSGeoffrey D. Bennett * 2nd Gen, 3rd Gen, 4th Gen, Clarett USB, Clarett+, and Vocaster 14*46757a3eSGeoffrey D. Bennett * series devices. 15*46757a3eSGeoffrey D. Bennett * 16*46757a3eSGeoffrey D. Bennett * The interface is provided via ALSA's hwdep interface. Opening the 17*46757a3eSGeoffrey D. Bennett * hwdep device requires CAP_SYS_RAWIO privileges as this interface 18*46757a3eSGeoffrey D. Bennett * provides near-direct access. 19*46757a3eSGeoffrey D. Bennett * 20*46757a3eSGeoffrey D. Bennett * For details on the FCP protocol, refer to the kernel scarlett2 21*46757a3eSGeoffrey D. Bennett * driver in sound/usb/mixer_scarlett2.c and the fcp-support project 22*46757a3eSGeoffrey D. Bennett * at https://github.com/geoffreybennett/fcp-support 23*46757a3eSGeoffrey D. Bennett * 24*46757a3eSGeoffrey D. Bennett * For examples of using these IOCTLs, see the fcp-server source in 25*46757a3eSGeoffrey D. Bennett * the fcp-support project. 26*46757a3eSGeoffrey D. Bennett * 27*46757a3eSGeoffrey D. Bennett * IOCTL Interface 28*46757a3eSGeoffrey D. Bennett * -------------- 29*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_PVERSION: 30*46757a3eSGeoffrey D. Bennett * Returns the protocol version supported by the driver. 31*46757a3eSGeoffrey D. Bennett * 32*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_INIT: 33*46757a3eSGeoffrey D. Bennett * Initialises the protocol and synchronises sequence numbers 34*46757a3eSGeoffrey D. Bennett * between the driver and device. Must be called at least once 35*46757a3eSGeoffrey D. Bennett * before sending commands. Can be safely called again at any time. 36*46757a3eSGeoffrey D. Bennett * 37*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_CMD: 38*46757a3eSGeoffrey D. Bennett * Sends an FCP command to the device and returns the response. 39*46757a3eSGeoffrey D. Bennett * Requires prior initialisation via FCP_IOCTL_INIT. 40*46757a3eSGeoffrey D. Bennett * 41*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_SET_METER_MAP: 42*46757a3eSGeoffrey D. Bennett * Configures the Level Meter control's mapping between device 43*46757a3eSGeoffrey D. Bennett * meters and control channels. Requires FCP_IOCTL_INIT to have been 44*46757a3eSGeoffrey D. Bennett * called first. The map size and number of slots cannot be changed 45*46757a3eSGeoffrey D. Bennett * after initial configuration, although the map itself can be 46*46757a3eSGeoffrey D. Bennett * updated. Once configured, the Level Meter remains functional even 47*46757a3eSGeoffrey D. Bennett * after the hwdep device is closed. 48*46757a3eSGeoffrey D. Bennett * 49*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_SET_METER_LABELS: 50*46757a3eSGeoffrey D. Bennett * Set the labels for the Level Meter control. Requires 51*46757a3eSGeoffrey D. Bennett * FCP_IOCTL_SET_METER_MAP to have been called first. labels[] 52*46757a3eSGeoffrey D. Bennett * should contain a sequence of null-terminated labels corresponding 53*46757a3eSGeoffrey D. Bennett * to the control's channels. 54*46757a3eSGeoffrey D. Bennett */ 55*46757a3eSGeoffrey D. Bennett #ifndef __UAPI_SOUND_FCP_H 56*46757a3eSGeoffrey D. Bennett #define __UAPI_SOUND_FCP_H 57*46757a3eSGeoffrey D. Bennett 58*46757a3eSGeoffrey D. Bennett #include <linux/types.h> 59*46757a3eSGeoffrey D. Bennett #include <linux/ioctl.h> 60*46757a3eSGeoffrey D. Bennett 61*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_MAJOR 2 62*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_MINOR 0 63*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_SUBMINOR 0 64*46757a3eSGeoffrey D. Bennett 65*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_VERSION \ 66*46757a3eSGeoffrey D. Bennett ((FCP_HWDEP_MAJOR << 16) | \ 67*46757a3eSGeoffrey D. Bennett (FCP_HWDEP_MINOR << 8) | \ 68*46757a3eSGeoffrey D. Bennett FCP_HWDEP_SUBMINOR) 69*46757a3eSGeoffrey D. Bennett 70*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_VERSION_MAJOR(v) (((v) >> 16) & 0xFF) 71*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_VERSION_MINOR(v) (((v) >> 8) & 0xFF) 72*46757a3eSGeoffrey D. Bennett #define FCP_HWDEP_VERSION_SUBMINOR(v) ((v) & 0xFF) 73*46757a3eSGeoffrey D. Bennett 74*46757a3eSGeoffrey D. Bennett /* Get protocol version */ 75*46757a3eSGeoffrey D. Bennett #define FCP_IOCTL_PVERSION _IOR('S', 0x60, int) 76*46757a3eSGeoffrey D. Bennett 77*46757a3eSGeoffrey D. Bennett /* Start the protocol */ 78*46757a3eSGeoffrey D. Bennett 79*46757a3eSGeoffrey D. Bennett /* Step 0 and step 2 responses are variable length and placed in 80*46757a3eSGeoffrey D. Bennett * resp[] one after the other. 81*46757a3eSGeoffrey D. Bennett */ 82*46757a3eSGeoffrey D. Bennett struct fcp_init { 83*46757a3eSGeoffrey D. Bennett __u16 step0_resp_size; 84*46757a3eSGeoffrey D. Bennett __u16 step2_resp_size; 85*46757a3eSGeoffrey D. Bennett __u32 init1_opcode; 86*46757a3eSGeoffrey D. Bennett __u32 init2_opcode; 87*46757a3eSGeoffrey D. Bennett __u8 resp[]; 88*46757a3eSGeoffrey D. Bennett } __attribute__((packed)); 89*46757a3eSGeoffrey D. Bennett 90*46757a3eSGeoffrey D. Bennett #define FCP_IOCTL_INIT _IOWR('S', 0x64, struct fcp_init) 91*46757a3eSGeoffrey D. Bennett 92*46757a3eSGeoffrey D. Bennett /* Perform a command */ 93*46757a3eSGeoffrey D. Bennett 94*46757a3eSGeoffrey D. Bennett /* The request data is placed in data[] and the response data will 95*46757a3eSGeoffrey D. Bennett * overwrite it. 96*46757a3eSGeoffrey D. Bennett */ 97*46757a3eSGeoffrey D. Bennett struct fcp_cmd { 98*46757a3eSGeoffrey D. Bennett __u32 opcode; 99*46757a3eSGeoffrey D. Bennett __u16 req_size; 100*46757a3eSGeoffrey D. Bennett __u16 resp_size; 101*46757a3eSGeoffrey D. Bennett __u8 data[]; 102*46757a3eSGeoffrey D. Bennett } __attribute__((packed)); 103*46757a3eSGeoffrey D. Bennett #define FCP_IOCTL_CMD _IOWR('S', 0x65, struct fcp_cmd) 104*46757a3eSGeoffrey D. Bennett 105*46757a3eSGeoffrey D. Bennett /* Set the meter map */ 106*46757a3eSGeoffrey D. Bennett struct fcp_meter_map { 107*46757a3eSGeoffrey D. Bennett __u16 map_size; 108*46757a3eSGeoffrey D. Bennett __u16 meter_slots; 109*46757a3eSGeoffrey D. Bennett __s16 map[]; 110*46757a3eSGeoffrey D. Bennett } __attribute__((packed)); 111*46757a3eSGeoffrey D. Bennett #define FCP_IOCTL_SET_METER_MAP _IOW('S', 0x66, struct fcp_meter_map) 112*46757a3eSGeoffrey D. Bennett 113*46757a3eSGeoffrey D. Bennett /* Set the meter labels */ 114*46757a3eSGeoffrey D. Bennett struct fcp_meter_labels { 115*46757a3eSGeoffrey D. Bennett __u16 labels_size; 116*46757a3eSGeoffrey D. Bennett char labels[]; 117*46757a3eSGeoffrey D. Bennett } __attribute__((packed)); 118*46757a3eSGeoffrey D. Bennett #define FCP_IOCTL_SET_METER_LABELS _IOW('S', 0x67, struct fcp_meter_labels) 119*46757a3eSGeoffrey D. Bennett 120*46757a3eSGeoffrey D. Bennett #endif /* __UAPI_SOUND_FCP_H */ 121