使用者空間 DTX (剪貼簿分離系統) 介面

surface_dtx 驅動程式負責正確的剪貼簿分離和重新連線處理。為此,它提供了 /dev/surface/dtx 裝置檔案,可以透過它與使用者空間守護程式互動。然後,此守護程式最終負責確定並採取必要的措施,例如解除安裝連線到基座的裝置、解除安裝/重新載入圖形驅動程式、使用者通知等。

此驅動程式中使用了兩個基本的通訊原則:命令(在文件的其他部分也稱為請求)和事件。命令被髮送到 EC,並且在不同的上下文中可能具有不同的含義。事件由 EC 在某些內部狀態更改時傳送。命令始終由驅動程式啟動,而事件始終由 EC 啟動。

命名法

  • 剪貼簿: Surface Book 的可分離上部,包含螢幕和 CPU。

  • 基座: Surface Book 的下部,剪貼簿可以從中分離,可以選擇(取決於型號)包含獨立 GPU (dGPU)。

  • 鎖閂: 在正常操作中將剪貼簿連線到基座的機制,並允許在請求時將其分離。

  • 靜默忽略的命令: 該命令被 EC 接受為有效命令並確認(遵循標準通訊協議),但 EC 不對其採取任何操作,即忽略它。

分離過程

警告:本文件的這一部分基於逆向工程和測試,因此可能包含錯誤或不完整。

鎖閂狀態

鎖閂機制有兩種主要狀態:開啟關閉。在關閉狀態(預設)下,剪貼簿固定到基座,而在開啟狀態下,使用者可以移除剪貼簿。

鎖閂還可以被鎖定和相應地解鎖,這可能會影響分離過程。具體而言,此鎖定機制旨在防止位於裝置基座中的 dGPU 在使用中時被熱插拔。有關更多詳細資訊,請參見下面的分離程式文件。預設情況下,鎖閂是解鎖的。

分離程式

請注意,分離過程完全由 EC 控制。surface_dtx 驅動程式僅將事件從 EC 中繼到使用者空間,並將命令從使用者空間中繼到 EC,即它不影響此過程。

分離過程從使用者按下裝置基座上的分離按鈕或執行 SDTX_IOCTL_LATCH_REQUEST IOCTL 開始。此後

  1. EC 開啟分離按鈕上的指示燈,傳送一個分離請求事件 (SDTX_EVENT_REQUEST),並等待進一步的指令/命令。如果鎖閂已解鎖,指示燈將閃爍綠色。如果鎖閂已鎖定,指示燈將呈紅色常亮。

  2. 該事件透過 surface_dtx 驅動程式中繼到使用者空間,使用者空間中的相應守護程式可以處理該事件並透過此驅動程式提供的 IOCTL 將指令發回 EC。

  3. EC 等待使用者空間的指令並根據指令執行操作。如果 EC 在給定的時間內未收到任何指令,它將超時並按以下方式繼續:

    • 如果鎖閂已解鎖,EC 將開啟鎖閂,並且剪貼簿可以從基座分離。這與沒有此驅動程式或任何使用者空間守護程式的情況下的行為完全相同。有關 EC 後續行為的更多詳細資訊,請參見下面的 SDTX_IOCTL_LATCH_CONFIRM 說明。

    • 如果鎖閂已鎖定,EC 將開啟鎖閂,這意味著剪貼簿無法從基座分離。此外,EC 傳送一個取消事件 (SDTX_EVENT_CANCEL),其中詳細說明了取消原因 SDTX_DETACH_TIMEDOUT(有關詳細資訊,請參見 事件)。

使用者空間守護程式對分離請求事件的有效響應是:

  • 執行 SDTX_IOCTL_LATCH_REQUEST。這將立即中止分離過程。此外,EC 將傳送一個分離請求事件,類似於使用者按下分離按鈕取消該過程(參見下文)。

  • 執行 SDTX_IOCTL_LATCH_CONFIRM。這將導致 EC 開啟鎖閂,之後使用者可以分離剪貼簿和基座。

    由於這會更改鎖閂狀態,因此一旦成功開啟鎖閂,將傳送一個鎖閂狀態事件 (SDTX_EVENT_LATCH_STATUS)。如果 EC 無法開啟鎖閂,例如由於硬體錯誤或電池電量不足,將傳送一個鎖閂取消事件 (SDTX_EVENT_CANCEL),取消原因表明具體故障。

    如果鎖閂當前已鎖定,則鎖閂將在開啟之前自動解鎖。

  • 執行 SDTX_IOCTL_LATCH_HEARTBEAT。這將重置內部超時。不會執行其他操作,即分離過程既不會完成也不會取消,並且 EC 仍將等待進一步的響應。

  • 執行 SDTX_IOCTL_LATCH_CANCEL。這將中止分離過程,類似於上面描述的 SDTX_IOCTL_LATCH_REQUEST 或下面描述的按鈕按下。作為對此的響應,將傳送一個通用請求事件 (SDTX_EVENT_REQUEST)。但是,與這些相反,如果沒有正在進行的分離過程,此命令不會觸發新的分離過程。

  • 不執行任何操作。分離過程最終會如第 3 點所述超時。

有關這些響應的更多詳細資訊,請參見 IOCTL

重要的是要注意,如果使用者在分離操作正在進行中的任何時候按下分離按鈕(即在 EC 傳送初始分離請求事件 (SDTX_EVENT_REQUEST) 之後,並在收到結束該過程的相應響應之前),分離過程將在 EC 級別取消,並且將傳送一個相同的事件。因此,分離請求事件本身並不表示分離過程的開始。

由於硬體故障或剪貼簿電池電量不足,EC 可能會進一步取消分離過程。這是透過一個取消事件 (SDTX_EVENT_CANCEL) 完成的,其中包含相應的取消原因。

使用者空間介面文件

錯誤程式碼和狀態值

錯誤和狀態程式碼分為不同的類別,可用於確定狀態程式碼是否為錯誤,如果是,則確定錯誤的嚴重性和型別。當前的類別是:

狀態/錯誤類別概述。

名稱

簡短描述

STATUS

0x0000

非錯誤狀態程式碼。

RUNTIME_ERROR

0x1000

非關鍵執行時錯誤。

HARDWARE_ERROR

0x2000

嚴重硬體故障。

UNKNOWN

0xF000

未知錯誤程式碼。

其他類別保留供將來使用。SDTX_CATEGORY() 宏可用於確定任何狀態值的類別。SDTX_SUCCESS() 宏可用於檢查狀態值是否為成功值 (SDTX_CATEGORY_STATUS) 或是否指示失敗。

EC 傳送的未知狀態或錯誤程式碼由驅動程式分配給 UNKNOWN 類別,並且將來可能會透過自己的程式碼實現。

當前使用的錯誤程式碼為:

錯誤程式碼概述。

名稱

類別

簡短描述

SDTX_DETACH_NOT_FEASIBLE

RUNTIME

0x1001

由於剪貼簿電池電量不足,無法分離。

SDTX_DETACH_TIMEDOUT

RUNTIME

0x1002

鎖閂鎖定時分離過程超時。

SDTX_ERR_FAILED_TO_OPEN

HARDWARE

0x2001

無法開啟鎖閂。

SDTX_ERR_FAILED_TO_REMAIN_OPEN

HARDWARE

0x2002

無法保持鎖閂開啟。

SDTX_ERR_FAILED_TO_CLOSE

HARDWARE

0x2003

無法關閉鎖閂。

其他錯誤程式碼保留供將來使用。非錯誤狀態程式碼可能會重疊,並且通常僅在其用例中是唯一的

鎖閂狀態程式碼。

名稱

類別

簡短描述

SDTX_LATCH_CLOSED

STATUS

0x0000

鎖閂已關閉/已關閉。

SDTX_LATCH_OPENED

STATUS

0x0001

鎖閂已開啟/已開啟。

基座狀態程式碼。

名稱

類別

簡短描述

SDTX_BASE_DETACHED

STATUS

0x0000

基座已分離/不存在。

SDTX_BASE_ATTACHED

STATUS

0x0001

基座已連線/存在。

同樣,其他程式碼保留供將來使用。

事件

可以透過從裝置檔案讀取來接收事件。預設情況下,它們處於停用狀態,必須先執行 SDTX_IOCTL_EVENTS_ENABLE 才能啟用。所有事件都遵循 struct sdtx_event 規定的佈局。特定事件型別可以透過其事件程式碼來識別,該程式碼在 enum sdtx_event_code 中描述。請注意,其他事件程式碼保留供將來使用,因此事件解析器必須能夠透過依賴事件頭中給出的有效負載長度來優雅地處理任何未知/不支援的事件型別。

當前提供的事件型別為:

DTX 事件概述。

名稱

程式碼

有效負載

簡短描述

SDTX_EVENT_REQUEST

1

0 位元組

分離過程已啟動/中止。

SDTX_EVENT_CANCEL

2

2 位元組

EC 取消了分離過程。

SDTX_EVENT_BASE_CONNECTION

3

4 位元組

基座連線狀態已更改。

SDTX_EVENT_LATCH_STATUS

4

2 位元組

鎖閂狀態已更改。

SDTX_EVENT_DEVICE_MODE

5

2 位元組

裝置模式已更改。

更詳細的各個事件

SDTX_EVENT_REQUEST

當用戶啟動或中止分離過程時傳送,可以透過按下分離按鈕或從使用者空間傳送分離請求 (SDTX_IOCTL_LATCH_REQUEST) 來實現。

沒有任何有效負載。

SDTX_EVENT_CANCEL

當 EC 由於未滿足的先決條件(例如,剪貼簿電池電量太低而無法分離)或硬體故障而取消分離過程時傳送。取消的原因在下面詳細說明的事件有效負載中給出,可以是以下之一:

  • SDTX_DETACH_TIMEDOUT:鎖閂鎖定時分離超時。鎖閂既沒有開啟也沒有解鎖。

  • SDTX_DETACH_NOT_FEASIBLE:由於剪貼簿電池電量不足,無法分離。

  • SDTX_ERR_FAILED_TO_OPEN:無法開啟鎖閂(硬體故障)。

  • SDTX_ERR_FAILED_TO_REMAIN_OPEN:無法保持鎖閂開啟(硬體故障)。

  • SDTX_ERR_FAILED_TO_CLOSE:無法關閉鎖閂(硬體故障)。

此上下文中的其他錯誤程式碼保留供將來使用。

這些程式碼可以透過 SDTX_CATEGORY() 宏進行分類,以區分關鍵硬體錯誤 (SDTX_CATEGORY_HARDWARE_ERROR) 或執行時錯誤 (SDTX_CATEGORY_RUNTIME_ERROR),如果未給出某些分離的先決條件,則後者可能在正常操作期間發生。

分離取消事件有效負載

欄位

型別

描述

reason

__u16

取消原因。

SDTX_EVENT_BASE_CONNECTION

當基座連線狀態已更改時傳送,即當基座已連線、分離或由於剪貼簿電池電量不足而導致分離變得不可行時。新狀態,如果基座已連線,則基座的 ID 作為 struct sdtx_base_info 型別的有效負載提供,其佈局如下所示:

基座連線更改事件有效負載

欄位

型別

描述

state

__u16

基座連線狀態。

base_id

__u16

連線的基座型別(如果沒有則為零)。

state 的可能值為:

  • SDTX_BASE_DETACHED,

  • SDTX_BASE_ATTACHED

  • SDTX_DETACH_NOT_FEASIBLE.

其他值保留供將來使用。

SDTX_EVENT_LATCH_STATUS

當鎖閂狀態已更改時傳送,即當鎖閂已開啟、關閉或發生錯誤時。當前狀態作為有效負載提供

鎖閂狀態更改事件有效負載

欄位

型別

描述

status

__u16

鎖閂狀態。

status 的可能值為:

  • SDTX_LATCH_CLOSED,

  • SDTX_LATCH_OPENED,

  • SDTX_ERR_FAILED_TO_OPEN,

  • SDTX_ERR_FAILED_TO_REMAIN_OPEN

  • SDTX_ERR_FAILED_TO_CLOSE.

其他值保留供將來使用。

SDTX_EVENT_DEVICE_MODE

當裝置模式已更改時傳送。新裝置模式作為有效負載提供

裝置模式更改事件有效負載

欄位

型別

描述

mode

__u16

裝置操作模式。

mode 的可能值為:

  • SDTX_DEVICE_MODE_TABLET,

  • SDTX_DEVICE_MODE_LAPTOP

  • SDTX_DEVICE_MODE_STUDIO.

其他值保留供將來使用。

IOCTL

提供了以下 IOCTL:

DTX IOCTL 概述

型別

編號

方向

名稱

描述

0xA5

0x21

-

EVENTS_ENABLE

為當前檔案描述符啟用事件。

0xA5

0x22

-

EVENTS_DISABLE

為當前檔案描述符停用事件。

0xA5

0x23

-

LATCH_LOCK

鎖定鎖閂。

0xA5

0x24

-

LATCH_UNLOCK

解鎖鎖閂。

0xA5

0x25

-

LATCH_REQUEST

請求剪貼簿分離。

0xA5

0x26

-

LATCH_CONFIRM

確認剪貼簿分離請求。

0xA5

0x27

-

LATCH_HEARTBEAT

向 EC 傳送心跳訊號。

0xA5

0x28

-

LATCH_CANCEL

取消分離過程。

0xA5

0x29

R

GET_BASE_INFO

獲取當前基座/連線資訊。

0xA5

0x2A

R

GET_DEVICE_MODE

獲取當前裝置操作模式。

0xA5

0x2B

R

GET_LATCH_STATUS

獲取當前裝置鎖閂狀態。

SDTX_IOCTL_EVENTS_ENABLE

定義為 _IO(0xA5, 0x22)

為當前檔案描述符啟用事件。如果啟用了事件,可以透過從裝置讀取來獲取事件。預設情況下,事件處於停用狀態。

SDTX_IOCTL_EVENTS_DISABLE

定義為 _IO(0xA5, 0x22)

為當前檔案描述符停用事件。如果啟用了事件,可以透過從裝置讀取來獲取事件。預設情況下,事件處於停用狀態。

SDTX_IOCTL_LATCH_LOCK

定義為 _IO(0xA5, 0x23)

鎖定鎖閂,導致分離過程中止,而不會在超時時開啟鎖閂。預設情況下,鎖閂是解鎖的。如果鎖閂已鎖定,此命令將被靜默忽略。

SDTX_IOCTL_LATCH_UNLOCK

定義為 _IO(0xA5, 0x24)

解鎖鎖閂,導致分離過程在超時時開啟鎖閂。預設情況下,鎖閂是解鎖的。如果在正在進行的分離過程中傳送此命令,它不會開啟鎖閂。如果鎖閂已解鎖,此命令將被靜默忽略。

SDTX_IOCTL_LATCH_REQUEST

定義為 _IO(0xA5, 0x25)

通用鎖閂請求。行為取決於上下文:如果沒有活動的分離過程,則請求分離。否則,當前活動的分離過程將被中止。

如果分離過程被此操作取消,將傳送一個通用分離請求事件 (SDTX_EVENT_REQUEST)。

這本質上與按下分離按鈕的行為相同。

SDTX_IOCTL_LATCH_CONFIRM

定義為 _IO(0xA5, 0x26)

確認並確認鎖閂請求。如果在正在進行的分離過程中傳送此命令,這將導致鎖閂立即開啟。如果鎖閂已鎖定,鎖閂也將開啟。在這種情況下,鎖閂鎖定將重置為解鎖狀態。

如果當前沒有正在進行的分離程式,此命令將被靜默忽略。

SDTX_IOCTL_LATCH_HEARTBEAT

定義為 _IO(0xA5, 0x27)

傳送心跳訊號,本質上是重置分離超時。當成功分離所需的工作仍在進行中時,可以使用此命令來保持分離過程的活動狀態。

如果當前沒有正在進行的分離程式,此命令將被靜默忽略。

SDTX_IOCTL_LATCH_CANCEL

定義為 _IO(0xA5, 0x28)

取消正在進行的分離(如果有)。如果分離過程被此操作取消,將傳送一個通用分離請求事件 (SDTX_EVENT_REQUEST)。

如果當前沒有正在進行的分離程式,此命令將被靜默忽略。

SDTX_IOCTL_GET_BASE_INFO

定義為 _IOR(0xA5, 0x29, struct sdtx_base_info)

獲取當前基座連線狀態(即已連線/已分離)以及連線到剪貼簿的基座型別。此命令本質上提供了一種查詢基座連線更改事件 (SDTX_EVENT_BASE_CONNECTION) 提供的資訊的方法。

struct sdtx_base_info.state 的可能值為:

  • SDTX_BASE_DETACHED,

  • SDTX_BASE_ATTACHED

  • SDTX_DETACH_NOT_FEASIBLE.

其他值保留供將來使用。

SDTX_IOCTL_GET_DEVICE_MODE

定義為 _IOR(0xA5, 0x2A, __u16)

返回裝置操作模式,指示基座是否以及如何連線到剪貼簿。此命令本質上提供了一種查詢裝置模式更改事件 (SDTX_EVENT_DEVICE_MODE) 提供的資訊的方法。

返回的值為:

  • SDTX_DEVICE_MODE_LAPTOP

  • SDTX_DEVICE_MODE_TABLET

  • SDTX_DEVICE_MODE_STUDIO

有關詳細資訊,請參見 struct sdtx_device_mode。其他值保留供將來使用。

SDTX_IOCTL_GET_LATCH_STATUS

定義為 _IOR(0xA5, 0x2B, __u16)

獲取當前鎖閂狀態或(大概)嘗試開啟/關閉鎖閂時遇到的最後一個錯誤。此命令本質上提供了一種查詢鎖閂狀態更改事件 (SDTX_EVENT_LATCH_STATUS) 提供的資訊的方法。

返回的值為:

  • SDTX_LATCH_CLOSED,

  • SDTX_LATCH_OPENED,

  • SDTX_ERR_FAILED_TO_OPEN,

  • SDTX_ERR_FAILED_TO_REMAIN_OPEN

  • SDTX_ERR_FAILED_TO_CLOSE.

其他值保留供將來使用。

關於基座 ID 的說明

透過 SDTX_EVENT_BASE_CONNECTIONSDTX_IOCTL_GET_BASE_INFO 提供的基座型別/ID 直接從 EC 轉發到組合 __u16 值的低位元組中,驅動程式將此 ID 來自的 EC 型別儲存在高位元組中(如果沒有這個,不同型別的 EC 上的基座 ID 可能會重疊)。

SDTX_DEVICE_TYPE() 宏可用於確定 EC 裝置型別。這可以是以下之一:

  • SDTX_DEVICE_TYPE_HID,用於透過 HID 的 Surface 聚合器模組,以及

  • SDTX_DEVICE_TYPE_SSH,用於透過 Surface 序列集線器的 Surface 聚合器模組。

請注意,目前僅支援 SSH 型別的 EC,但是 HID 型別保留供將來使用。

結構體和列舉

enum sdtx_device_mode

描述剪貼簿如何(以及是否)連線到裝置基座的模式。

常量

SDTX_DEVICE_MODE_TABLET

剪貼簿已從基座分離,並且裝置作為平板電腦執行。

SDTX_DEVICE_MODE_LAPTOP

剪貼簿正常連線到基座,並且裝置作為筆記型電腦執行。

SDTX_DEVICE_MODE_STUDIO

剪貼簿反向連線到基座。裝置作為平板電腦執行,鍵盤和觸控板已停用,但是基座電池以及(如果在特定裝置型號中存在)dGPU 可用於系統。

struct sdtx_event

透過從 DTX 裝置檔案讀取提供的事件。

定義:

struct sdtx_event {
    __u16 length;
    __u16 code;
    __u8 data[];
};

成員

length

事件有效負載的長度(以位元組為單位)。

code

事件程式碼,詳細說明這是什麼型別的事件。

data

事件的有效負載,包含 length 位元組。

描述

有關當前有效的事件程式碼,請參見 enum sdtx_event_code

enum sdtx_event_code

描述事件型別的程式碼。

常量

SDTX_EVENT_REQUEST

分離請求事件型別。

SDTX_EVENT_CANCEL

取消分離過程事件型別。

SDTX_EVENT_BASE_CONNECTION

基座/剪貼簿連線更改事件型別。

SDTX_EVENT_LATCH_STATUS

鎖閂狀態更改事件型別。

SDTX_EVENT_DEVICE_MODE

裝置模式更改事件型別。

描述

struct sdtx_event 中使用,以描述事件的型別。進一步的事件程式碼保留供將來使用。任何事件解析器都應該能夠優雅地處理未知事件,即透過簡單地跳過它們。

有關各個事件型別的詳細資訊,請查閱 DTX 使用者空間介面文件。

struct sdtx_base_info

描述底座是否已連線以及連線的型別。

定義:

struct sdtx_base_info {
    __u16 state;
    __u16 base_id;
};

成員

state

連線狀態。有效值為 SDTX_BASE_DETACHEDSDTX_BASE_ATTACHEDSDTX_DETACH_NOT_FEASIBLE(如果底座已連線但剪貼簿電池電量低,無法分離)。其他值目前保留。

base_id

連線的底座型別。如果沒有底座連線,則為零。

API 使用者

使用此 API 的使用者空間守護程式可以在 https://github.com/linux-surface/surface-dtx-daemon 中找到。