feat: support for USB mass storage devices, hotplugging

This commit is contained in:
2026-05-18 17:47:12 +02:00
parent f8e8af1d78
commit 41d2841cc9
36 changed files with 1537 additions and 130 deletions
+1 -1
View File
@@ -291,7 +291,7 @@ namespace Montauk {
struct DiskInfo {
uint8_t port; // block device index
uint8_t type; // 0=none, 1=SATA, 2=SATAPI, 3=NVMe
uint8_t type; // 0=none, 1=SATA, 2=SATAPI, 3=NVMe, 4=USB mass storage
uint8_t sataGen; // SATA gen (1/2/3)
uint8_t _pad0;
uint64_t sectorCount; // Total user-addressable sectors
+3 -1
View File
@@ -88,10 +88,12 @@ static void dd_draw_general(uint32_t* px, int bw, int bh, DiskDetailState* dd) {
const char* typeStr = "Unknown";
if (dd->info.type == 1) typeStr = "SATA";
else if (dd->info.type == 2) typeStr = "SATAPI";
else if (dd->info.type == 3) typeStr = "NVMe";
else if (dd->info.type == 4) typeStr = "USB Mass Storage";
table_row("Type", typeStr);
snprintf(line, sizeof(line), "%d", (int)dd->info.port);
table_row("AHCI Port", line);
table_row("Device Index", line);
px_hline(px, bw, bh, x + 8, y, w - 16, border);
y += 12;
+5 -3
View File
@@ -46,10 +46,11 @@ void open_newpart_dialog() {
dlg.hover_cancel = false;
Montauk::DiskInfo& disk = dt.disks[dt.selected_disk];
int blockDev = selected_block_dev();
char sz[24];
format_disk_size(sz, sizeof(sz), disk.sectorCount, disk.sectorSizeLog);
snprintf(dlg.disk_desc, sizeof(dlg.disk_desc), "Disk %d: %s (%s)",
dt.selected_disk, disk.model, sz);
blockDev, disk.model, sz);
if (dlg.will_init_gpt) {
snprintf(dlg.warn_line1, sizeof(dlg.warn_line1),
@@ -89,7 +90,8 @@ void newpart_dialog_confirm() {
auto& dlg = dt.np_dlg;
if (dlg.will_init_gpt) {
int r = montauk::gpt_init(dt.selected_disk);
int blockDev = selected_block_dev();
int r = montauk::gpt_init(blockDev);
if (r < 0) {
set_status("Failed to initialize GPT on disk");
close_newpart_dialog();
@@ -100,7 +102,7 @@ void newpart_dialog_confirm() {
Montauk::GptAddParams params;
montauk::memset(&params, 0, sizeof(params));
params.blockDev = dt.selected_disk;
params.blockDev = selected_block_dev();
params.startLba = 0;
params.endLba = 0;
params.typeGuid.Data1 = 0xEBD0A0A2;
+8 -3
View File
@@ -31,7 +31,7 @@ static constexpr int ITEM_H = 32;
static constexpr int MAP_H = 48;
static constexpr int MAP_PAD = 16;
static constexpr int MAX_PARTS = 32;
static constexpr int MAX_DISKS = 8;
static constexpr int MAX_DISKS = 32;
static constexpr int STATUS_H = 44;
static constexpr int TB_BTN_Y = 7;
@@ -120,8 +120,11 @@ extern const Color part_colors[NUM_PART_COLORS];
// ============================================================================
inline int disk_button_width(int idx) {
char label[8];
snprintf(label, sizeof(label), "Disk %d", idx);
char label[16];
int blockDev = (idx >= 0 && idx < g_state.disk_count)
? (int)g_state.disks[idx].port
: idx;
snprintf(label, sizeof(label), "Disk %d", blockDev);
return text_width(label) + 20;
}
@@ -192,6 +195,8 @@ inline Rect dialog_secondary_button_rect(int dialog_w, int dialog_h) {
// ============================================================================
void set_status(const char* msg);
int disk_block_dev(int diskIndex);
int selected_block_dev();
int get_disk_parts(int* indices, int max);
void format_disk_size(char* buf, int bufsize, uint64_t sectors, uint16_t sectorSize);
+13 -1
View File
@@ -40,10 +40,22 @@ void set_status(const char* msg) {
g_state.status_time = montauk::get_milliseconds();
}
int disk_block_dev(int diskIndex) {
if (diskIndex < 0 || diskIndex >= g_state.disk_count) return -1;
return (int)g_state.disks[diskIndex].port;
}
int selected_block_dev() {
return disk_block_dev(g_state.selected_disk);
}
int get_disk_parts(int* indices, int max) {
int blockDev = selected_block_dev();
if (blockDev < 0) return 0;
int count = 0;
for (int i = 0; i < g_state.part_count && count < max; i++) {
if (g_state.parts[i].blockDev == g_state.selected_disk) {
if (g_state.parts[i].blockDev == blockDev) {
indices[count++] = i;
}
}
+2 -2
View File
@@ -93,8 +93,8 @@ static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
for (int i = 0; i < dt.disk_count; i++) {
Rect button = toolbar_disk_button_rect(i);
char label[8];
snprintf(label, sizeof(label), "Disk %d", i);
char label[16];
snprintf(label, sizeof(label), "Disk %d", disk_block_dev(i));
mtk::draw_button(c, button, label, mtk::BUTTON_SECONDARY,
toolbar_button_state(button, true, i == dt.selected_disk), theme);
}
+2 -2
View File
@@ -649,14 +649,14 @@ static void install_single_fat32(int disk) {
void do_install() {
auto& st = g_state;
int disk = st.selected_disk;
if (disk < 0 || disk >= st.disk_count) {
if (st.selected_disk < 0 || st.selected_disk >= st.disk_count) {
st.step = STEP_ERROR;
add_log("No disk selected");
flush_ui();
return;
}
int disk = (int)st.disks[st.selected_disk].port;
g_files_copied = 0;
g_dirs_created = 0;
+1 -1
View File
@@ -28,7 +28,7 @@ static constexpr int INIT_H = 440;
static constexpr int TOOLBAR_H = 36;
static constexpr int STEP_BAR_H = 32;
static constexpr int CONTENT_TOP = TOOLBAR_H + STEP_BAR_H;
static constexpr int MAX_DISKS = 8;
static constexpr int MAX_DISKS = 32;
static constexpr int MAX_PARTS = 32;
static constexpr int STATUS_H = 26;
+4 -2
View File
@@ -207,7 +207,8 @@ static void render_select_disk(uint32_t* px) {
char info[64], sz[24];
format_disk_size(sz, sizeof(sz), st.disks[i].sectorCount, st.disks[i].sectorSizeLog);
const char* dtype = st.disks[i].rpm == 1 ? "SSD" : "HDD";
snprintf(info, sizeof(info), "%s %s (Disk %d)", sz, dtype, i);
snprintf(info, sizeof(info), "%s %s (Disk %d)", sz, dtype,
(int)st.disks[i].port);
px_text(px, g_win_w, g_win_h, item_x + 32, y + 6 + fh + 2, info, DIM_TEXT, FONT_SM);
y += item_h + 4;
@@ -301,7 +302,8 @@ static void render_confirm(uint32_t* px) {
format_disk_size(sz, sizeof(sz), st.disks[st.selected_disk].sectorCount,
st.disks[st.selected_disk].sectorSizeLog);
snprintf(desc, sizeof(desc), "Disk %d: %s (%s)",
st.selected_disk, st.disks[st.selected_disk].model, sz);
(int)st.disks[st.selected_disk].port,
st.disks[st.selected_disk].model, sz);
px_text(px, g_win_w, g_win_h, (g_win_w - text_w(desc)) / 2, y, desc, TEXT_COLOR);
y += fh + 16;