A deep dive into Apple Touch Bar - Part I
Recent Apple MacBook Pro models are usually equipped with long OLED touch display that officially named “Touch Bar” that substitutes the traditional Function (Fn) key row. Internally, this thing is called Dynamic Function Row (DFR) according to the naming prefix of related system components. In Boot Camp Windows installations, the Touch Bar acts as basic media and function keys without advanced graphical capabilities.
Given the fact that the Touch Bar is implemented by either Apple T1 or T2 chip, it is certain that one or more connection technology such as USB are utilized for the host communication. However, the communication protocol remains unknown for a long time due to the availability(cost) of device and the nature of typical technology users.
Third-party developers have developed applications that simulates Touch Bar on the host (x86) system. A quick inspection through the source code reveals a library that generates the continuous stream that contains the graphical content on the Touch Bar. It suggests that the content on Touch Bar is pre-rendered on the x86 system and gets transferred to the ARM side (T1/T2). Since T1 and T2 are both connected on the USB bus, packet captures were conducted over the USB bus.
Packet capture over the USB bus
During packet capture sessions, the pattern of periodic large packet transfers were observed. However, the size is not fully deterministic, but mostly it is larger than 54000 bytes. More image with certain patterns (single color, rainbow, etc.) were transferred to help analysis the binary structure. With sufficient samples, the following characteristics and structs were concluded:
- A semi-static header is present for each frame update.
- Raw pixels are transferred in BGR24 format.
- There was a static padding at the end.
typedef struct _DFR_GENERIC_REQUEST_CONTENT {
UINT32 RequestKey;
UCHAR Reserved[8];
UINT32 End;
} DFR_GENERIC_REQUEST_CONTENT, *PDFR_GENERIC_REQUEST_CONTENT;
typedef struct _DFR_GENERIC_REQUEST {
DFR_GENERIC_REQUEST_HEADER Header;
DFR_GENERIC_REQUEST_CONTENT Content;
} DFR_GENERIC_REQUEST, *PDFR_GENERIC_REQUEST;
typedef struct _DFR_UPDATE_FB_REQUEST_CONTENT {
UINT16 Reserved0;
UINT8 FrameId;
UINT8 Reserved1;
UINT32 Reserved2;
UCHAR Reserved3[24];
UINT16 BeginX;
UINT16 BeginY;
UINT16 Width;
UINT16 Height;
UINT32 BufferSize;
} DFR_UPDATE_FB_REQUEST_CONTENT, *PDFR_UPDATE_FB_REQUEST_CONTENT;
typedef struct _DFR_UPDATE_FB_REQUEST {
DFR_GENERIC_REQUEST_HEADER Header;
DFR_UPDATE_FB_REQUEST_CONTENT Content;
} DFR_UPDATE_FB_REQUEST, *PDFR_UPDATE_FB_REQUEST;