xHCI/BOT driver: genuine multi-device support (FABRIC-3.md §VII)
Per-slot registry (xhci_msc_slot_t/dev->msc_slots, sized off the controller's own reported max_slots) replaces the single-device scalar fields the driver carried since Milestones 2e-2h. Boot-time port scan no longer stops at the first connected device; a connect/disconnect that arrives while the Command Ring is busy is now queued and drained instead of dropped. blkio_usb.c and repl.c's own single-device state (device descriptor buffers, blkio_dev_t, attach bookkeeping) became per-slot registries the same way. Live multi-device testing (not just compiling) surfaced a second, more severe bug outside the original plan: transfer_purpose and next_action were also single scalars shared across the whole controller. Two devices enumerating concurrently could have one's completion silently overwrite the other's still-outstanding one, permanently stalling it with no error. Fixed by moving both per-slot and, critically, reading the Transfer Event TRB's own real Slot ID field instead of trusting external bookkeeping. Verified live, all three architectures, mandatory clean-qemu acceptance: existing single-device path unchanged, and two devices attached simultaneously (amd64) both progress independently through enumeration without corrupting or stalling each other. Also in this pass (implemented and verified in earlier turns this session, committed together per direct instruction): - Headless-until-login console policy: no prompt/banner until a real identity logs in via an attached thumbdrive (WIREBIND or Zuse, neither special), reusing EMERGENCY_CONSOLE_ENABLED as the debug/recovery escape hatch (now default-off). - KILL/g_repl_active_vm dangling-pointer fix: killing the VM the console is currently USE'd onto now detaches back to Hera first, matching the existing EJECT/UNCLEAN precedent. FABRIC-3.md §VII/§VIII carry full closure notes for all three. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018EjXFo7mPXjUMjfJeuUUz4
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
cc6fcb6a0b
commit
9e81de3f43
@@ -203,6 +203,11 @@ void capsule_wirebind_try_attach(struct blkio_dev *dev,
|
||||
g_wirebind_attached_dev = dev;
|
||||
memcpy(g_wirebind_attached_username, username, sizeof(g_wirebind_attached_username));
|
||||
|
||||
/* Decided 2026-09-05: no console for the running system unless a
|
||||
* thumbdrive is present -- this successful console+user VM birth is
|
||||
* exactly that login. See repl.h's own doc comment. */
|
||||
sk_console_mark_login();
|
||||
|
||||
/* Register the pairing in the console's own routing table, index 3
|
||||
* -- the fixed convention sk_repl_dispatch_line() (repl.c) uses. */
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "starkernel/zuse_genesis_marker.h"
|
||||
#include "starkernel/user_identity_seed.h"
|
||||
#include "starkernel/console.h"
|
||||
#include "starkernel/repl.h" /* sk_console_mark_login() -- FABRIC-2.md headless-until-login gate */
|
||||
#include "block_subsystem.h" /* compute_crc64(), blk_meta_zone_read/write */
|
||||
#include "blkio.h"
|
||||
#include <string.h>
|
||||
@@ -74,6 +75,13 @@ static void install_and_activate(VM *mama_vm, const uint8_t seed[32], const uint
|
||||
* convention. */
|
||||
vm_interpret(mama_vm, "ACL-ZUSE-BOOT");
|
||||
g_zuse_attached_this_device = 1;
|
||||
|
||||
/* Decided 2026-09-05: no console for the running system unless a
|
||||
* thumbdrive is present. Zuse's own login is not special here --
|
||||
* "nothing special about zuse as a user except zuse has no ACLs,"
|
||||
* per direct instruction -- so this is the same shared signal
|
||||
* capsule_wirebind.c's own successful login sets. See repl.h. */
|
||||
sk_console_mark_login();
|
||||
}
|
||||
|
||||
void capsule_zuse_boot_try_attach(struct blkio_dev *dev,
|
||||
|
||||
@@ -571,9 +571,20 @@ void mama_word_kill(VM *vm)
|
||||
{
|
||||
VMRegistryEntry entry;
|
||||
if (capsule_vm_find_by_name_nocase(name_buf, &entry) == 0 &&
|
||||
entry.state == VM_STATE_LIVE &&
|
||||
!vm_uuid_is_hera(entry.vm_id)) {
|
||||
vm_physics_retire(entry.vm_id);
|
||||
entry.state == VM_STATE_LIVE) {
|
||||
if (!vm_uuid_is_hera(entry.vm_id)) {
|
||||
vm_physics_retire(entry.vm_id);
|
||||
}
|
||||
/* FABRIC-2.md §F.10, real bug found and reported 2026-08-27,
|
||||
* fixed 2026-09-05: capsule_vm_kill() never touches
|
||||
* g_repl_active_vm -- killing the VM the console is currently
|
||||
* USE'd onto left it dangling (the REPL would fault on the
|
||||
* next command dispatched through it). EJECT/UNCLEAN
|
||||
* (capsule_wirebind.c) already reset-before-kill this way;
|
||||
* plain KILL's own call site never did. */
|
||||
if (entry.vm_ptr && sk_repl_get_active_vm() == (VM *) entry.vm_ptr) {
|
||||
sk_repl_set_active_vm((VM *) 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -929,6 +929,21 @@ static void kernel_main_deep(BootInfo *boot_info) {
|
||||
}
|
||||
console_println("");
|
||||
|
||||
/* Decided 2026-09-05: no console for the running system unless a
|
||||
* thumbdrive is present -- headless by default (EMERGENCY_CONSOLE_
|
||||
* ENABLED off), reusing that flag's own existing "does this build
|
||||
* expose an unauthenticated interactive escape surface" posture
|
||||
* (Kconfig.heartbeat) rather than adding a second, overlapping one.
|
||||
* When off, sk_repl_headless_wait() runs the same idle-tick services
|
||||
* (heartbeat, USB/WIREBIND/Zuse-attach detection) with no banner, no
|
||||
* prompt, no input surface at all, until sk_console_mark_login()
|
||||
* fires from either login path -- neither is treated as special, per
|
||||
* direct instruction. When on (the debug/recovery escape hatch),
|
||||
* this is skipped entirely and the console shows up immediately,
|
||||
* exactly as before this change. */
|
||||
#if !EMERGENCY_CONSOLE_ENABLED
|
||||
sk_repl_headless_wait(mama);
|
||||
#endif
|
||||
sk_repl(mama);
|
||||
#endif
|
||||
|
||||
|
||||
+103
-20
@@ -37,6 +37,7 @@
|
||||
#include "starkernel/arch.h"
|
||||
#include "starkernel/xhci_driver.h"
|
||||
#include "starkernel/blkio_usb.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "starkernel/homeblocks_sig.h"
|
||||
#include "starkernel/capsule_birth.h"
|
||||
#include "starkernel/capsule_zuse_boot.h"
|
||||
@@ -96,6 +97,19 @@ static VM *g_repl_active_vm = (void *)0;
|
||||
void sk_repl_set_active_vm(VM *vm) { g_repl_active_vm = vm; }
|
||||
VM *sk_repl_get_active_vm(void) { return g_repl_active_vm; }
|
||||
|
||||
/*===========================================================================
|
||||
* Headless-until-login gate, decided 2026-09-05: no console for the
|
||||
* running system unless a thumbdrive is present. One shared flag, set by
|
||||
* either login path (capsule_wirebind.c's regular-user console-VM birth,
|
||||
* capsule_zuse_boot.c's own attach/genesis-mint) -- neither is special,
|
||||
* per direct instruction. See repl.h's own doc comments.
|
||||
*===========================================================================*/
|
||||
|
||||
static int g_console_login_occurred = 0;
|
||||
|
||||
void sk_console_mark_login(void) { g_console_login_occurred = 1; }
|
||||
int sk_console_login_occurred(void) { return g_console_login_occurred; }
|
||||
|
||||
/*===========================================================================
|
||||
* Currently attached home-blocks device: mirrors g_repl_active_vm's own
|
||||
* shape (FABRIC-2.md §F.9's own precedent for this exact accessor). Set
|
||||
@@ -228,14 +242,33 @@ static void sk_repl_idle(VM *active_vm)
|
||||
* busy-wait -- which blkio_usb_open_msc() uses internally -- must
|
||||
* never run from inside xhci_poll_events()'s own call frame). */
|
||||
xhci_dev_t *xdev = xhci_get_dev();
|
||||
static blkio_dev_t usb_blk_dev; /* single-device scope, matching the xHCI
|
||||
* driver's own; referenced by both the
|
||||
* attach and detach handling below. */
|
||||
if (xdev && xdev->bot_msc_attach_pending) {
|
||||
xdev->bot_msc_attach_pending = 0;
|
||||
uint32_t slot_id = xdev->bot_msc_attach_slot_id;
|
||||
/* FABRIC-3.md §VII (2026-09-05): was `static blkio_dev_t usb_blk_dev`
|
||||
* ("single-device scope, matching the xHCI driver's own") -- now a
|
||||
* per-slot registry, same sizing/allocation precedent as xhci_dev_t's
|
||||
* own msc_slots[] (sized off xdev->max_slots, allocated once on first
|
||||
* idle tick after xdev is known, since this file has no bringup-time
|
||||
* hook of its own). Every slot with a pending attach/detach flag is
|
||||
* serviced this tick, not just one -- a single `if` here used to mean
|
||||
* a second device's pending flag would sit unnoticed until the first's
|
||||
* flag was consumed and cleared. */
|
||||
static blkio_dev_t *usb_blk_dev_slots = (void *)0;
|
||||
static uint32_t usb_blk_dev_slot_count = 0;
|
||||
if (xdev && (!usb_blk_dev_slots || usb_blk_dev_slot_count < xdev->max_slots + 1)) {
|
||||
size_t bytes = (size_t)(xdev->max_slots + 1) * sizeof(blkio_dev_t);
|
||||
blkio_dev_t *fresh = (blkio_dev_t *)kmalloc_aligned(bytes, 64);
|
||||
if (fresh) {
|
||||
memset(fresh, 0, bytes);
|
||||
usb_blk_dev_slots = fresh;
|
||||
usb_blk_dev_slot_count = xdev->max_slots + 1;
|
||||
}
|
||||
}
|
||||
for (uint32_t slot_id = 1; xdev && usb_blk_dev_slots && slot_id <= xdev->max_slots; slot_id++) {
|
||||
xhci_msc_slot_t *ms = xhci_msc_slot_for(xdev, slot_id);
|
||||
if (!ms || !ms->bot_msc_attach_pending) continue;
|
||||
ms->bot_msc_attach_pending = 0;
|
||||
blkio_dev_t *usb_blk_dev = &usb_blk_dev_slots[slot_id];
|
||||
|
||||
int rc = blkio_usb_open_msc(&usb_blk_dev, xdev, slot_id);
|
||||
int rc = blkio_usb_open_msc(usb_blk_dev, xdev, slot_id);
|
||||
if (rc == 0) {
|
||||
/* FABRIC-2.md Milestone 4: warn on blank/foreign/unrecognized
|
||||
* media -- the "warn" half. No "refuse" half yet: blkio_usb.c
|
||||
@@ -254,11 +287,22 @@ static void sk_repl_idle(VM *active_vm)
|
||||
* interim value (FABRIC-2.md §F.8/§F.13). */
|
||||
homeblocks_sig_t sig;
|
||||
homeblocks_sig_result_t sig_rc =
|
||||
homeblocks_sig_check(&usb_blk_dev, HOMEBLOCKS_SIG_START_FBLOCK, &sig);
|
||||
homeblocks_sig_check(usb_blk_dev, HOMEBLOCKS_SIG_START_FBLOCK, &sig);
|
||||
switch (sig_rc) {
|
||||
case HOMEBLOCKS_SIG_OK:
|
||||
log_message(LOG_DEBUG, "xhci: USB drive recognized as a home-blocks drive");
|
||||
g_homeblocks_dev = &usb_blk_dev;
|
||||
/* FABRIC-3.md §VII (2026-09-05): g_homeblocks_dev/
|
||||
* g_attached_blk_dev stay single "most recently
|
||||
* attached" pointers by deliberate, scoped choice --
|
||||
* the multi-device fix's target was the driver/backend
|
||||
* corrupting each other's live state when two devices
|
||||
* are attached at once (fixed above and in xhci.c/
|
||||
* blkio_usb.c), not making every console-facing FORTH
|
||||
* word (RUNCAP et al, mama_forth_words.c) multi-device
|
||||
* aware -- the console still interacts with one device
|
||||
* at a time, matching its own single-active-REPL
|
||||
* design. Revisit if a real use case needs otherwise. */
|
||||
g_homeblocks_dev = usb_blk_dev;
|
||||
g_homeblocks_sig = sig;
|
||||
g_homeblocks_sig_valid = 1;
|
||||
break;
|
||||
@@ -284,7 +328,7 @@ static void sk_repl_idle(VM *active_vm)
|
||||
* be detected before the REPL's own idle polling exists to
|
||||
* detect it). No-ops immediately if Zuse already has a real
|
||||
* identity this boot. */
|
||||
capsule_zuse_boot_try_attach(&usb_blk_dev, sig_rc, &sig, (VM *)sk_get_mama_vm());
|
||||
capsule_zuse_boot_try_attach(usb_blk_dev, sig_rc, &sig, (VM *)sk_get_mama_vm());
|
||||
|
||||
/* FABRIC-2.md §F.5/§F.23 (WIREBIND): the real thumbdrive-
|
||||
* attach call site for a regular (non-Zuse) identity --
|
||||
@@ -295,12 +339,12 @@ static void sk_repl_idle(VM *active_vm)
|
||||
* itself no-ops for a genesis-mode Zuse drive (no cert
|
||||
* region) or before Zuse has authenticated this boot. */
|
||||
if (sig_rc == HOMEBLOCKS_SIG_OK) {
|
||||
capsule_wirebind_try_attach(&usb_blk_dev, &sig, (VM *)sk_get_mama_vm());
|
||||
capsule_wirebind_try_attach(usb_blk_dev, &sig, (VM *)sk_get_mama_vm());
|
||||
}
|
||||
}
|
||||
if (rc == 0 && blk_subsys_attach_device(&usb_blk_dev) == BLK_OK) {
|
||||
xdev->bot_msc_attached = 1;
|
||||
g_attached_blk_dev = &usb_blk_dev;
|
||||
if (rc == 0 && blk_subsys_attach_device(usb_blk_dev) == BLK_OK) {
|
||||
ms->bot_msc_attached = 1;
|
||||
g_attached_blk_dev = usb_blk_dev;
|
||||
} else {
|
||||
log_message(LOG_ERROR, "xhci: USB MSC block-subsystem attach failed");
|
||||
}
|
||||
@@ -312,15 +356,21 @@ static void sk_repl_idle(VM *active_vm)
|
||||
* no device round-trip, so it wouldn't strictly need to run outside
|
||||
* xhci_poll_events()'s own call frame -- but handling it here anyway
|
||||
* matches the attach path's shape and keeps xhci.c decoupled from
|
||||
* block_subsystem.c (see bot_msc_detach_pending's own doc comment). */
|
||||
if (xdev && xdev->bot_msc_detach_pending) {
|
||||
xdev->bot_msc_detach_pending = 0;
|
||||
blk_subsys_detach_device(&usb_blk_dev);
|
||||
if (g_homeblocks_dev == &usb_blk_dev) {
|
||||
* block_subsystem.c (see bot_msc_detach_pending's own doc comment).
|
||||
* Per-slot loop now (FABRIC-3.md §VII, 2026-09-05), same reasoning as
|
||||
* the attach loop above. */
|
||||
for (uint32_t slot_id = 1; xdev && usb_blk_dev_slots && slot_id <= xdev->max_slots; slot_id++) {
|
||||
xhci_msc_slot_t *ms = xhci_msc_slot_for(xdev, slot_id);
|
||||
if (!ms || !ms->bot_msc_detach_pending) continue;
|
||||
ms->bot_msc_detach_pending = 0;
|
||||
blkio_dev_t *usb_blk_dev = &usb_blk_dev_slots[slot_id];
|
||||
|
||||
blk_subsys_detach_device(usb_blk_dev);
|
||||
if (g_homeblocks_dev == usb_blk_dev) {
|
||||
g_homeblocks_dev = (void *)0;
|
||||
g_homeblocks_sig_valid = 0;
|
||||
}
|
||||
if (g_attached_blk_dev == &usb_blk_dev) {
|
||||
if (g_attached_blk_dev == usb_blk_dev) {
|
||||
g_attached_blk_dev = (void *)0;
|
||||
}
|
||||
|
||||
@@ -576,6 +626,25 @@ int sk_console_getkey(VM *active_vm)
|
||||
}
|
||||
}
|
||||
|
||||
/* sk_repl_headless_wait - see repl.h's own doc comment. Same idle-service
|
||||
* shape as sk_console_getkey() above, minus the key-reading entirely: no
|
||||
* banner, no prompt, no console_getc()/readline of any kind -- this is
|
||||
* exactly the "no console for the running system unless a thumbdrive is
|
||||
* present" boundary, decided 2026-09-05. Exits the moment
|
||||
* sk_console_login_occurred() becomes true. */
|
||||
void sk_repl_headless_wait(VM *mama)
|
||||
{
|
||||
while (!sk_console_login_occurred()) {
|
||||
heartbeat_service();
|
||||
uint64_t now = heartbeat_ticks();
|
||||
if (now - g_last_beat_tick >= SK_IDLE_BEAT_INTERVAL) {
|
||||
g_last_beat_tick = now;
|
||||
sk_repl_idle(mama);
|
||||
}
|
||||
arch_relax();
|
||||
}
|
||||
}
|
||||
|
||||
/* ?TERMINAL's real body (sf_terminal_ready(), shim.c): non-blocking peek --
|
||||
* a single poll, no idle-servicing loop (a false result must return
|
||||
* immediately, not block). Buffers a found byte in g_console_pending_key so
|
||||
@@ -911,8 +980,16 @@ int sk_repl_step(VM *vm)
|
||||
vm->abort_requested = 0;
|
||||
|
||||
if (vm->error) {
|
||||
#if EMERGENCY_CONSOLE_ENABLED
|
||||
console_puts(" ERROR\n");
|
||||
vm->error = 0;
|
||||
#else
|
||||
/* Wired 2026-09-05: sk_fault_handler() existed but was never
|
||||
* called from here -- the "halts VM on error" half of this
|
||||
* function's own doc comment was aspirational, not real, until
|
||||
* now. Real for the headless-until-login default. */
|
||||
sk_fault_handler(vm);
|
||||
#endif
|
||||
} else {
|
||||
console_puts(" ok\n");
|
||||
}
|
||||
@@ -955,8 +1032,14 @@ void sk_repl_run(VM *vm)
|
||||
active->abort_requested = 0;
|
||||
|
||||
if (active->error) {
|
||||
#if EMERGENCY_CONSOLE_ENABLED
|
||||
console_puts(" ERROR\n");
|
||||
active->error = 0;
|
||||
#else
|
||||
/* Wired 2026-09-05, same as sk_repl_step()'s matching branch
|
||||
* above -- sk_fault_handler() existed but was never called. */
|
||||
sk_fault_handler(active);
|
||||
#endif
|
||||
} else {
|
||||
console_puts(" ok\n");
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "starkernel/blkio_usb.h"
|
||||
#include "starkernel/kmalloc.h"
|
||||
#include "console.h"
|
||||
|
||||
typedef struct {
|
||||
@@ -22,16 +23,39 @@ typedef struct {
|
||||
uint32_t total_forth_blocks;
|
||||
} BlkioUsbState;
|
||||
|
||||
/* Singleton — one USB MSC device (single-outstanding-transaction scope,
|
||||
* matching the xHCI driver this backend sits on). */
|
||||
static BlkioUsbState g_usb_blk;
|
||||
/* FABRIC-3.md §VII (2026-09-05): was a single static instance ("one USB MSC
|
||||
* device, single-outstanding-transaction scope, matching the xHCI driver
|
||||
* this backend sits on") -- now a per-slot registry, same shape and same
|
||||
* sizing precedent as xhci_dev_t's own msc_slots (registry sized off the
|
||||
* controller's own max_slots, allocated once on first use here since this
|
||||
* file has no bringup-time hook of its own to do it earlier). Indexed
|
||||
* directly by xHCI slot ID, index 0 unused, matching msc_slots[]. */
|
||||
static BlkioUsbState *g_usb_blk_slots = NULL;
|
||||
static uint32_t g_usb_blk_slot_count = 0;
|
||||
|
||||
static BlkioUsbState *usb_blk_state_for(xhci_dev_t *xdev, uint32_t slot_id) {
|
||||
if (!xdev || slot_id < 1 || slot_id > xdev->max_slots) return NULL;
|
||||
if (!g_usb_blk_slots || g_usb_blk_slot_count < xdev->max_slots + 1) {
|
||||
size_t bytes = (size_t)(xdev->max_slots + 1) * sizeof(BlkioUsbState);
|
||||
BlkioUsbState *fresh = (BlkioUsbState *)kmalloc_aligned(bytes, 64);
|
||||
if (!fresh) return NULL;
|
||||
memset(fresh, 0, bytes);
|
||||
g_usb_blk_slots = fresh;
|
||||
g_usb_blk_slot_count = xdev->max_slots + 1;
|
||||
}
|
||||
return &g_usb_blk_slots[slot_id];
|
||||
}
|
||||
|
||||
static int usb_blk_open(blkio_dev_t *dev, const blkio_params_t *p) {
|
||||
(void)p;
|
||||
if (!dev) return BLKIO_EINVAL;
|
||||
dev->state = &g_usb_blk;
|
||||
/* FABRIC-3.md §VII (2026-09-05): blkio_open() zeroes dev->state before
|
||||
* calling this (see blkio.h), so the per-slot BlkioUsbState* this
|
||||
* device should use travels in through p->opaque -- set by
|
||||
* blkio_usb_open_msc() below -- rather than a single module-global. */
|
||||
if (!dev || !p || !p->opaque) return BLKIO_EINVAL;
|
||||
BlkioUsbState *s = (BlkioUsbState *)p->opaque;
|
||||
dev->state = s;
|
||||
dev->forth_block_size = BLKIO_FORTH_BLOCK_SIZE;
|
||||
dev->total_blocks = g_usb_blk.total_forth_blocks;
|
||||
dev->total_blocks = s->total_forth_blocks;
|
||||
return BLKIO_OK;
|
||||
}
|
||||
|
||||
@@ -110,6 +134,9 @@ static const blkio_vtable_t g_usb_blk_vtable = {
|
||||
int blkio_usb_open_msc(blkio_dev_t *dev_out, xhci_dev_t *xdev, uint32_t slot_id) {
|
||||
if (!dev_out || !xdev) return -1;
|
||||
|
||||
BlkioUsbState *s = usb_blk_state_for(xdev, slot_id);
|
||||
if (!s) return -1;
|
||||
|
||||
if (xhci_bot_get_capacity(xdev, slot_id) != 0) return -1;
|
||||
if (xhci_bot_wait_for_idle(xdev, 100000u) != BOT_STATUS_PASS) return -1;
|
||||
|
||||
@@ -123,11 +150,11 @@ int blkio_usb_open_msc(blkio_dev_t *dev_out, xhci_dev_t *xdev, uint32_t slot_id)
|
||||
uint32_t blocks_per_fblock = BLKIO_FORTH_BLOCK_SIZE / block_size;
|
||||
uint64_t total_forth_blocks = total_scsi_blocks / blocks_per_fblock;
|
||||
|
||||
g_usb_blk.xdev = xdev;
|
||||
g_usb_blk.slot_id = slot_id;
|
||||
g_usb_blk.scsi_block_size = block_size;
|
||||
g_usb_blk.scsi_blocks_per_fblock = blocks_per_fblock;
|
||||
g_usb_blk.total_forth_blocks = (total_forth_blocks > 0xFFFFFFFFull)
|
||||
s->xdev = xdev;
|
||||
s->slot_id = slot_id;
|
||||
s->scsi_block_size = block_size;
|
||||
s->scsi_blocks_per_fblock = blocks_per_fblock;
|
||||
s->total_forth_blocks = (total_forth_blocks > 0xFFFFFFFFull)
|
||||
? 0xFFFFFFFFu
|
||||
: (uint32_t)total_forth_blocks;
|
||||
|
||||
@@ -135,8 +162,8 @@ int blkio_usb_open_msc(blkio_dev_t *dev_out, xhci_dev_t *xdev, uint32_t slot_id)
|
||||
|
||||
blkio_params_t params;
|
||||
params.forth_block_size = BLKIO_FORTH_BLOCK_SIZE;
|
||||
params.total_blocks = g_usb_blk.total_forth_blocks;
|
||||
params.opaque = NULL;
|
||||
params.total_blocks = s->total_forth_blocks;
|
||||
params.opaque = s;
|
||||
|
||||
return blkio_open(dev_out, &g_usb_blk_vtable, ¶ms);
|
||||
}
|
||||
|
||||
+490
-383
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user