使用者空間 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 開始。此後
EC 開啟分離按鈕上的指示燈,傳送一個分離請求事件 (
SDTX_EVENT_REQUEST),並等待進一步的指令/命令。如果鎖閂已解鎖,指示燈將閃爍綠色。如果鎖閂已鎖定,指示燈將呈紅色常亮。該事件透過
surface_dtx驅動程式中繼到使用者空間,使用者空間中的相應守護程式可以處理該事件並透過此驅動程式提供的 IOCTL 將指令發回 EC。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) 完成的,其中包含相應的取消原因。
使用者空間介面文件¶
錯誤程式碼和狀態值¶
錯誤和狀態程式碼分為不同的類別,可用於確定狀態程式碼是否為錯誤,如果是,則確定錯誤的嚴重性和型別。當前的類別是:
名稱 |
值 |
簡短描述 |
|---|---|---|
|
|
非錯誤狀態程式碼。 |
|
|
非關鍵執行時錯誤。 |
|
|
嚴重硬體故障。 |
|
|
未知錯誤程式碼。 |
其他類別保留供將來使用。SDTX_CATEGORY() 宏可用於確定任何狀態值的類別。SDTX_SUCCESS() 宏可用於檢查狀態值是否為成功值 (SDTX_CATEGORY_STATUS) 或是否指示失敗。
EC 傳送的未知狀態或錯誤程式碼由驅動程式分配給 UNKNOWN 類別,並且將來可能會透過自己的程式碼實現。
當前使用的錯誤程式碼為:
名稱 |
類別 |
值 |
簡短描述 |
|---|---|---|---|
|
|
|
由於剪貼簿電池電量不足,無法分離。 |
|
|
|
鎖閂鎖定時分離過程超時。 |
|
|
|
無法開啟鎖閂。 |
|
|
|
無法保持鎖閂開啟。 |
|
|
|
無法關閉鎖閂。 |
其他錯誤程式碼保留供將來使用。非錯誤狀態程式碼可能會重疊,並且通常僅在其用例中是唯一的
名稱 |
類別 |
值 |
簡短描述 |
|---|---|---|---|
|
|
|
鎖閂已關閉/已關閉。 |
|
|
|
鎖閂已開啟/已開啟。 |
名稱 |
類別 |
值 |
簡短描述 |
|---|---|---|---|
|
|
|
基座已分離/不存在。 |
|
|
|
基座已連線/存在。 |
同樣,其他程式碼保留供將來使用。
事件¶
可以透過從裝置檔案讀取來接收事件。預設情況下,它們處於停用狀態,必須先執行 SDTX_IOCTL_EVENTS_ENABLE 才能啟用。所有事件都遵循 struct sdtx_event 規定的佈局。特定事件型別可以透過其事件程式碼來識別,該程式碼在 enum sdtx_event_code 中描述。請注意,其他事件程式碼保留供將來使用,因此事件解析器必須能夠透過依賴事件頭中給出的有效負載長度來優雅地處理任何未知/不支援的事件型別。
當前提供的事件型別為:
名稱 |
程式碼 |
有效負載 |
簡短描述 |
|---|---|---|---|
|
|
|
分離過程已啟動/中止。 |
|
|
|
EC 取消了分離過程。 |
|
|
|
基座連線狀態已更改。 |
|
|
|
鎖閂狀態已更改。 |
|
|
|
裝置模式已更改。 |
更詳細的各個事件
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),如果未給出某些分離的先決條件,則後者可能在正常操作期間發生。
欄位 |
型別 |
描述 |
|---|---|---|
|
|
取消原因。 |
SDTX_EVENT_BASE_CONNECTION¶
當基座連線狀態已更改時傳送,即當基座已連線、分離或由於剪貼簿電池電量不足而導致分離變得不可行時。新狀態,如果基座已連線,則基座的 ID 作為 struct sdtx_base_info 型別的有效負載提供,其佈局如下所示:
欄位 |
型別 |
描述 |
|---|---|---|
|
|
基座連線狀態。 |
|
|
連線的基座型別(如果沒有則為零)。 |
state 的可能值為:
SDTX_BASE_DETACHED,SDTX_BASE_ATTACHED和SDTX_DETACH_NOT_FEASIBLE.
其他值保留供將來使用。
SDTX_EVENT_LATCH_STATUS¶
當鎖閂狀態已更改時傳送,即當鎖閂已開啟、關閉或發生錯誤時。當前狀態作為有效負載提供
欄位 |
型別 |
描述 |
|---|---|---|
|
|
鎖閂狀態。 |
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 的可能值為:
SDTX_DEVICE_MODE_TABLET,SDTX_DEVICE_MODE_LAPTOP和SDTX_DEVICE_MODE_STUDIO.
其他值保留供將來使用。
IOCTL¶
提供了以下 IOCTL:
型別 |
編號 |
方向 |
名稱 |
描述 |
|---|---|---|---|---|
|
|
|
|
為當前檔案描述符啟用事件。 |
|
|
|
|
為當前檔案描述符停用事件。 |
|
|
|
|
鎖定鎖閂。 |
|
|
|
|
解鎖鎖閂。 |
|
|
|
|
請求剪貼簿分離。 |
|
|
|
|
確認剪貼簿分離請求。 |
|
|
|
|
向 EC 傳送心跳訊號。 |
|
|
|
|
取消分離過程。 |
|
|
|
|
獲取當前基座/連線資訊。 |
|
|
|
|
獲取當前裝置操作模式。 |
|
|
|
|
獲取當前裝置鎖閂狀態。 |
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_LAPTOPSDTX_DEVICE_MODE_TABLETSDTX_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_CONNECTION 或 SDTX_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_DETACHED、SDTX_BASE_ATTACHED和SDTX_DETACH_NOT_FEASIBLE(如果底座已連線但剪貼簿電池電量低,無法分離)。其他值目前保留。base_id連線的底座型別。如果沒有底座連線,則為零。
API 使用者¶
使用此 API 的使用者空間守護程式可以在 https://github.com/linux-surface/surface-dtx-daemon 中找到。