#shkwve: an incomplete kernel/maybe bootloader/UEFI thing/maybe something else if i get bored again
1 messages · Page 2 of 1
oh right btw
i noticed that you do some detection or whatever for usb3?
which you dont really need, like at all
you get problems if you reset a usb3 port
thats what the spec says at least
what do you mean by that
a USB2 port, after attach, is disabled (PED=0)
a USB3 port, after attach, is enabled (PED=1)
page 84, 4.3
uuuh I suppose
so you don't need to actually check the capabilities
I didn't actually consider that
meanwhile, my laziness and lack of desire for more weird structure parsing:
a usb3 device is not attached when polling
its only considered attached when it enters the Enabled state
?
static void FUSL_xhci_enqueue_impl(struct FUSL_XHCIController *controller, struct FUSL_XHCIQueue const *q, uint32_t dw0, uint32_t dw1, uint32_t dw2, uint32_t dw3) {
uint32_t volatile *access = (uint32_t volatile *)(q->phys.fusl_address + q->offset);
access[0] = dw0;
access[1] = dw1;
access[2] = dw2;
// you are missing a fence here
access[3] = dw3 | q->cycle_state;
controller->controller.callbacks.pflush(&controller->controller, q->phys, q->offset, 0x10);
}
the first 3 writes must go out before the last one
yes enough
it is enough
but you shouldnt use an atomic
wait what invariants does fusl actually require
?
like what kind of guarantees does palloc give you
why does he need a barrier there, its volatile so the compiler is not allowed to reorder those fields
or accesses to them rather
oh it is
because the cpu can reorder them
lol
i dont think so no
maybe
AM?
abstract machine
yeah it doesnt guard against any sort of cpu reordering
is there any case where pinvalidate wouldn't handle this correctly on a real cpu? @untold basin
I can't think of one
on arm you're gonna have the entire struct in one cacheline and flush it all at once
wdym?
i think you just need two flushes
write first 3 fields, flush, write last field, flush
why isn't what I do correct
I don't think it's incorrect in practice
because the entire trb is in one cacheline
because your api contract does not include this constraint that the entire trb is one cacheline
isn't that an XHCI requirement?
that all TRBs are 0x10 aligned?
this assumes that cache lines are more than 0x10 bytes :^)
which is technically not a requirement
yes, that's what I mean with any real cpu
is there any real cpu with less than 0x10 bytes of cacheline?
shit ass microcontrollers
with a dwc3 because the vendor got the ip on the cheap
no way
is there a builtin to get the cacheline size
no
i wonder if it returns 64 bytes on m1 :^)
is it not?
nope its 128
nice then I can write a thing to detect if it's m1 or not
oh interesting its 128 on x86 too apparantly
what??
you are guaranteed at least 64 on x86 and arm tho
idk man thats what zig source tells me
// x86_64: Starting from Intel's Sandy Bridge, the spatial prefetcher pulls in pairs of 64-byte cache lines at a time.
// - https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-optimization-manual.pdf
// - https://github.com/facebook/folly/blob/1b5288e6eea6df074758f877c849b6e73bbb9fbb/folly/lang/Align.h#L107
//
// aarch64: Some big.LITTLE ARM archs have "big" cores with 128-byte cache lines:
// - https://www.mono-project.com/news/2016/09/12/arm64-icache/
// - https://cpufun.substack.com/p/more-m1-fun-hardware-information
//
// powerpc64: PPC has 128-byte cache lines
// - https://github.com/golang/go/blob/3dd58676054223962cd915bb0934d1f9f489d4d2/src/internal/cpu/cpu_ppc64x.go#L9
.x86_64, .aarch64, .powerpc64 => 128,
actually hmm nevermind
anyways I can't imagine a platform with cachelines smaller than 0x10 and having an XHCI controller
so I'll consider it fine
but I can add a comment there
at least put a c11 seqcst thread fence between them
but seqcst 🤢
er, signal fence
fine
not thread fence
atomic_signal_fence(memory_order_seq_cst)
signal fence == compiler reordering
and its spec since c11
i meant signal fence not thread fence
the signal fence is a compiler reordering barrier, not a "real" barrier
ehh it stops almost everything
mfence();
slot.add(0).write_volatile(values[0]);
slot.add(1).write_volatile(values[1]);
slot.add(2).write_volatile(values[2]);
mfence();
slot.add(3).write_volatile(values[3] | self.flip);
``` lol i have volatile and also mfence
ew lol
mfence is a riscv fence (arm dmb sy iirc)
but just asm("DMB ST"); 🥴
nah i use it in other places as a store-load fence
its fine
its not that much worse
hm i should probably add fences to the managarm xhci driver too :^)
yeah on x86 the 32-bit writes are all atomic anyway
and if it works on the two arms that are real its fine
it does work on the arms because the cachelines are large enough
while they are probably not needed
id much rather not have my driver fail inexplicably
well on the pi4 you need to flush after the writes because the pcie controller is not cache coherent
the pflush does that
the possible bug pitust brings up is the 4th store happening before any of the first 3
although you still don't need fences because all the flush completes before the doorbell is rung
and that won't happen on any real CPU
the queue could be currently running
right?
ah true yes
or does it always halt before raising an interrupt/completion TRB
at least in like normal scenarios
an interrupt only happens when the trb has a flag set
not when it stops processing trbs
okay but it triggers on the first one with the flag, while it's running?
it pushes events for every retired trb with the flag set, and i think the event ring raises the interrupt as long as the event ring is not empty
yeah it's gotta because keep going since otherwise it would just leave TRBs there unprocessed
yeah
yeah so the ring could be running during that then
actually i do think i have a very hypothetical case where this could fuck up
xhci emulation, in a vm, running on a sibling hyperthread
so it would be an issue if a TRB could be split into multiple cachelines

elaborate
if the vm on a different hyperthread polls the cache line, it can easily see the values out of order
because hyperthreads share caches
let me think
dont think its super realistic tbh
if it can happen I will fix it
if not I won't
I'm starting to think it could be an issue anyways
the write to the last dword could finish first anyways
and have the cacheline written back
because the first 3 stores could depend on a pending load or some shit
I think I need the fence, straight up
that's not even a contrived example
and the last one may not
q_push(q, uncached_ptr->a, uncached_ptr->b, uncached_ptr->c, 0);
here it's even likely the last store happens first
I will fix it, thanks
but why are you unhappy with the store-release
I think it's the perfectly scoped thing
since it only says "this store needs to wait for all the other stores to finish"
idk i wouldnt trust it all that much
also its an atomic being used to device stuff
it does nothing I don't need and everything I need
no it's not device memory
not mmio
it's device "stuff" not device memory
also you explicitly permit the memory to be mapped UC
in which case atomics wont work
good catch, thanks
in the "cause faults" way
does C11 have a plain store barrier
a release fence?
or just call pflush 
eh?
yes you can pass memory_order_release to atomic_thread_fence
pflush guarantees the writes go out to ram
so it's a release fence
oh right the order says that thanks
atomic_thread_fence(memory_order_release);
anyways how do you feel about the code quality of FUSL @untold basin now that you've read it
and then ig an atomic store?
too strict
doesn't work on UC
UC
pretty nice
definitely a lot better than my shitty xhci non-driver
okay thanks
I take those
although i call the rings rings instead of queues
only thing i call the same as the spec :^)
call them ring queues :^)
what about queue rings /j
that sounds like a ring of queues
nah its Ring and EventRing
where in actuality its a ring of rings
at least the one specified by the interruptor register at offset 10h is a ring of rings
distinction without a difference :^)
i dont remember the real name
i have Ring for the command rings and EventRing for the event ring
because they have different code
they dont
which is a really interesting property
eh?
oh well in memory they do
but my control struct for them is different
because an event ring stores the interruptor associated as well
in managarm it's ProducerRing and EventRing
thats a better name
lol no
most consistent naming in mammogram
i just ring the doorbell every time
producer/consumer? no, producer/event
woo shit ass drivering
if it makes the device do vaguely what i intended it to do its working
shhh
mammogram? i thought its mangraman, the managed code operating system 
well ConsumerRing would obscure what it actually is imo
since it's specifically dealing with the event ring
but ProducerRing woudn't?
that's a good one
the code for it has no specific command/transfer related methods
but I don't like the idea of using device
it's just a ring you can push trbs to
maybe HostToXHCRing
hah I beat you
its the obvious name
way faster
but dont worry im sure fusl doesnt beat my code for supporting scratch buffers ```rs
let num_scratch_buf = ((hcs2 >> 16) & 0x3E) as usize | (hcs2 >> 27) as usize;
if num_scratch_buf != 0 {
log::error!("{node} xhci: xhc wants {num_scratch_buf} buffers");
return;
}
its truly unbeatable
amazing
if (wants any) well shit()
vs the event ring which handles the dequeing and it parses the trbs into Events before passing them on to the controller event dispatch function
fucking cheap shit hardware designers
cant even put ram into their xhc's
it's not that, it's that the host os should restore them on suspend/resume
AAAAAAAAAAH
just accidentally restore it with random values to see what happens
it's very cool and completely useless
also i don't think linux does that
yeah just reinit the fucking usb devices lol
its not like they arent going to rehotplug
but that's observable from the device and will break someones workflow
so the spec has to account for that guy
the fact that the OS suspended is also quite observable tho
I love how Intel literally got one guy'd when writing the XHCI spec
it can be seen by the fact that literally every laptop i have kills device power
when you suspend
so none of this matters anyway!
"I need to be able to write entire controller state and usb topology to disk and restore after suspend"
"yeah sure that seems perfectly sensible, let's add that"
it may not be if the suspend keeps device power
always on usb ports are a thing
i love how intel put potentially useful things not in the xhci spec but in their chipset-specific documentation so there's no generic way to do them
like changing the bandwidth allocation between different port types
on intel controllers you can write to some chipset-specific mmio addresses inside the xhci controller
oh i think i havent had one lol
ever?
but cool ig
they're nice for charging phones and nothing else
yeah only reason to have one
usually marked red
and a phone is fine with getting reinited
it might be difficult to mark a typec red tho
and i have all typec now
what if it's a scuffed usb powered iot device
then it can go die
or get a powerbank enterprise-grade UPS
lol
and if you need data, well then fuck you
a 5$ powerbank does the job just as well tho
good luck finding more than a single cell for that price
the cheapest definitely not fraud powerbanks on amazon are like 8 euros
intel accounted for everything in xhci (except the 40 something quirks linux has to account for)
how to start a house fire in 3 simple steps, step 1:
no, the step 1 is this marvel
if you buy 2 you save 10%!
(15.5 gbp shipping)
no way i have one of those in a drawer somewhere
lmfao
no way qookie is getting a house fire
hasn't caused a fire in the few years it's spent in a drawer so it's fine :^)
the cell is probably completely dead though
it wasn't great to begin with
of course i mean its the cheapest powerbank money can buy in bulk from shenzen
okay lets figure out the rest of the usb
considering i bought it in person and not over the internet, if you factor in the shipping i think i paid less
(plus 15.49 gbp shipping)
wow scam shipping
but it was years ago and i don't remember the price
oh, amazon has those now?
well
I thought it was exclusively fraud
not obviously fraud
theres also kindles which arent fraud either
like yk the official listings
@untold basin now that I have that fence there I don't need volatile anymore right
that's nicer in one way
i think you need volatile?
idk
uint32_t *access = (uint32_t *)(q->phys.fusl_address + q->offset);
access[0] = dw0;
access[1] = dw1;
access[2] = dw2;
atomic_thread_fence(memory_order_release);
access[3] = dw3 | q->cycle_state;
controller->controller.callbacks.pflush(&controller->controller, q->phys, q->offset, 0x10);
for what
to make sure the c compiler doesnt have any stupid ideas lol
volatile is free though
what would it be allowed to do
fair point
but i have had run ins with compilers doing wild shit before
it would prevent things like STP X2, X3, [X1] in this case
it would have to be split into two STRs
true
I don't think it's needed in C in this case, just C++
ugh I'm not sure
and this is exactly why you should use volatile
fuck it you're right
i managed to make a transfer i think!
data
aaand that looks like the data i got
nice
this guy implemented a usb stack in two days
3
also calling it a stack is a bit of a stretch
"jenga tower" fits much better
also its massively scuffed
so i guess the next step is figuring out which usb device driver to use
more real descriptor parsing
oh, oops, read the wrong descriptor
thats the right one
@short kraken i found another fusl bug
static uint32_t calculate_exponent(uint32_t microframes) {
uint32_t result;
while((1 << result) < microframes) {
++result;
}
return result + 3;
}
your calculate_exponent function invokes undefined behavior
gcc seems to deal with it fine
but clang uses this innovative approach to calculating an exponent: ```x86asm
calculate_exponent:
ret
known as "just dont lol"
also you write the enable endpoint mask twice, once in FUSL_xhci_reevaluate_endpoint and once in FUSL_xhci_enable_endpoint
wtf
i mean its random so clang is correct
lol
yeah
if its so good at figuring out that this is ub why cant it let me know tho
instead of silently removing it
or is it because of fusl warning level
its kinda hard to figure out how to report it
it's also not LLVM UB
i think
hmm maybe it is llvm ub?
idk but probably not
"result is used uninitialized"
but how do you PROVE that it is in fact uninitialized
that isn't an error necessarily
also with -Wall -Wextra -Werror it probs would fail
yep <source>:4:15: error: variable 'result' is uninitialized when used here [-Werror,-Wuninitialized] 4 | while((1 << result) < microframes) { | ^~~~~~
the part that proves it's UB is way later than the part that can show you a diagnostic
surely its a solvable problem lol
its kinda really hard to solve it
especially without impacting compile perf
at least afaik
oh also i think i managed to accidentally make a HID data request
by accident
also its kinda annoying that they dont tell you about NAKs
because i dont really have a good way of detecting that afaict?
hmm is the xhc guaranteed to process shit i tell it in order
theres no way right
yeah i think there isnt
that is really fucking annoying
whatever
oh i should probably issue the SetConfiguartion thing too
oh whoops forgot = 0;
yeah
reevaluate endpoint is called for ep0 and is for correcting the packet size
the other api is for every other endpoint
ah i see i see
enable doesn't send the matching command to the xhc
which is weird
unless im missing something which is very likely
after setting all the new parameters for the endpoint
like the type and max packet size and whatever else
you need to issue a control endpoint trb
i think?
no?
or at least without it qemu doesnt print the happy line of usb_xhci_ep_enable slotid 1, epid 3
you're not changing anything except what packet size the controller uses when sending to/from the device
i mean at some point you have to start making transfers though
to like not the control endpoint
yes?
and to do that you need to enable the endpoint
which requires a control endpoint trb
if you set the max packet size to 8, a 16 byte data transfer will be split into 2 8 byte packets
yeah that's different
that your FUSL_xhci_enable_endpoint doesn't enable endpoints
it sets up shit to do so, but then doesn't issue the TRB for it
are you saying there's a control transfer for enabling endpoints?
I thought you just set the configuration and get all the endpoints on said configuration
no, there is a TRB type for it
like you need to tell the XHC to make the endpoint work
I'm sending the configure endpoint thing, no?
void FUSL_xhci_configure_device(struct FUSL_XHCIPhysicalDevice *dev, uint8_t configuration_value) {
struct FUSL_XHCIController *controller = (struct FUSL_XHCIController *)dev->pdev.pdev.controller;
struct FUSL_XHCIInputControlContext *icc = (struct FUSL_XHCIInputControlContext *)dev->pdev.device_phys.fusl_address;
icc->a |= 1;
icc->config = configuration_value;
struct FUSL_XHCISlotContext *isc = (struct FUSL_XHCISlotContext *)(dev->pdev.device_phys.fusl_address + (0x20 << controller->csz));
isc->context_entries = 31;
controller->controller.callbacks.pflush(&controller->controller, dev->pdev.device_phys, 0, 0x40 << controller->csz);
FUSL_xhci_enqueue_command(controller, SPLIT(dev->pdev.device_phys.device_address), 0, ((dev->slot + 1) << 24) | (TRBT_CONFIGURE_ENDPOINT << 10));
}
oh
I havn't pushed this yet
void FUSL_xhci_configure_device(struct FUSL_XHCIPhysicalDevice *dev, uint8_t configuration_value) {
struct FUSL_XHCIController *controller = (struct FUSL_XHCIController *)dev->pdev.pdev.controller;
struct FUSL_XHCIInputControlContext *icc = (struct FUSL_XHCIInputControlContext *)dev->pdev.device_phys.fusl_address;
icc->a |= 1;
icc->config = configuration_value;
struct FUSL_XHCISlotContext *isc = (struct FUSL_XHCISlotContext *)(dev->pdev.device_phys.fusl_address + (0x20 << controller->csz));
isc->context_entries = 31;
}
lol
yeah okay
fair
okay you're caught up with where I was a few weeks ago then lol
I still havn't gone ahead and packaged this into commits yet
ah okay cool
lol
right now im trying to get the hid config
and im just getting stalls
somehow
get the hid config?
you mean the configuration descriptor?
if so, what control transfer are you sending?
no i mean the HID report
did you set the configuration
and issue the SET_CONFIGURATION control transfer (or not set the suppress bit in TRBT_CONFIGURE_ENDPOINT)?
yes
wait whats the suppress bit?
there's a bit you can set which supresses sending SET_CONFIGURATION
iirc the controller sends it for you if you don't set it
its not in the pcap :^)
indeed lul
actually
I think I'm thinking of address device/SET_ADDRESS
not the configuration
yeah right, that's correct
+ FUSL_control_transfer_flat(pdev, &(struct FUSL_ControlTransfer) {
+ .value = cdesc->configuration_value,
+ .request = 0x09,
+ .type = 0x00,
+ .length = 0,
+ .index = 0,
+ }, 0, 0, true);
that's something I do separately
oh nvm
i think im just sending a garbage control transfer
oh yeah
i changed the wrong bit
yeah
okay now im getting the right hid report descriptor
contents: ```c
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x06, // Usage (Keyboard)
0xA1, 0x01, // Collection (Application)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0xE0, // Usage Minimum (0xE0)
0x29, 0xE7, // Usage Maximum (0xE7)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x05, 0x08, // Usage Page (LEDs)
0x19, 0x01, // Usage Minimum (Num Lock)
0x29, 0x05, // Usage Maximum (Kana)
0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0xFF, // Logical Maximum (-1)
0x05, 0x07, // Usage Page (Kbrd/Keypad)
0x19, 0x00, // Usage Minimum (0x00)
0x29, 0xFF, // Usage Maximum (0xFF)
0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
// 63 bytes
(qemu usb kbd)
and now i have to figure out how to deal with NAKs
wait does NAK mean "come back later"?
or "i dont have any data"
interrupt eps should automatically deal with NAKs by just trying the transfer later
ahh
does that happen at the xhci level?
por que no los dos
yeah
xhci just retries the usb-level transfer after every interval, and the trb chain completes after the first non-NAK response
oh!!!
nice
apart from it being pcaped as isochronous
that is broken
and weird
wrong bits in the ep context?
for isoch eps i think at every interval the device has to respond with data, so a nak would cause the trb to fail
but it's not failing
which is weird
also i do have to use the right kind of endpoint right?
i cant just make up that it's an isoch now
yeah isoch has some special requirements
and bulk vs interrupt differ in the polling behavior i think?
not too sure about that
i see
i think i have broken event ring code tbh
oh i fixed it cool!
okay time to make intr endpoints work in a non crappy way
probably by doing something which involves queues and unparking or something like that
or maybe ill figure out how to do multi trait RTTI work
hmm i still dont know how i should make the xhci transfer api work
because transfer can block
and rust + async = just no
ah i guess fusl just uses callbacks
and i dont know how id make that work with the shitty lang im using
and my equally shitty driver model
i mean i guess i could make my driver model less shitty 😛
actually thats probably doable
yep
and also it makes buffer ownership annoying
function pointer in the device struct gets called on transfer completion
yeah i see i see
what's the difference between a control transfer and a data transfer?
ah hmm
wait i dont get it
control transfer sends some data to the device in the setup packet, then sends or receives some data in the data stage, then ends with a status packet
i see
😦 but i wanna
polling get report sounds a lot easier than making interrupt transfers work
(i probably will need them for cdc anyway lol)
the problem is basically that the buffer for a control transfer is effectively owned by the xhc
you can put the setup packet data straight in the trb
instead of via a pointer to a buffer
oh i see
thats interesting ig
okay yes and hotplug vaguely works
im still not sure how to handle transfers yet
maybe ill do pubsub?
or something idk
not only that, you HAVE to
also qemu ignores this bit for non-setup packets
so you will get problems if you try to use it for anything else
it's not and even qemu will spit in your face if you don't use it
interesting
i wasnt super careful in implementing the spec because i was mostly copying fusl
i should probably fix that then
well fusl does set this bit
hmm
ok maybe im fine then?
ugh async transfers are a pain
can the device NAK a control transfer?
wonderful
which is even worse
stall is another way of saying fail right?
or just pretend the device doesnt exist anymore
yes
you can treat it as a fatal device error if you don't care about mass storage
mass storage randomly stalls all the time
only for bulk and interrupt eps
or well
on the xhci side for all eps
yes
but also on the device side for bulk and intr eps
lovely
by sending some request on the control pipe
also for ls/fs devices anywhere behind a hs hub you need to issue CLEAR_TT_BUFFER for the port the device is on to the closest hs hub
managarm has all the logic except for the hs hub stuff
not sure how well it works since i haven't implemented the usb msd driver handling stalls yet
but it's needed to retry with a different read/write command if the one you tried faild
it wouldn't even be that hard to do either
e.g. if read10 is not supported and it stalls
each device can just keep track of FUSL_Hub *upstream_hs_hub; which would get inherited from the parent
and set to the parent if it's the first non-hs one in the tree
yeah i was thinking of doing that in managarm too
each device has a parent hub ptr but it could also just have a parent tt ptr, which would point to the hs hub
otoh the hierarchy is at most 6 deep
so you can just follow the parents and look for the first hs one
I mean the route string only has 5 fields so yeah
for fucks sake
void FUSL_init_pdev(struct FUSL_Controller *controller, struct FUSL_PhysicalDeviceImpl *pdev, struct FUSL_Hub *parent, uint32_t parent_port, uint32_t speed) {
pdev->pdev.controller = controller;
pdev->pdev.parent_hub = parent;
pdev->pdev.parent_port = parent_port;
pdev->pdev.speed = speed;
if(parent) {
pdev->pdev.depth = parent->device.physical_device->depth + 1;
pdev->pdev.route_string = parent->device.physical_device->route_string | (pdev->pdev.parent_port << ((parent->device.physical_device->depth) * 5));
pdev->pdev.root_port = parent->device.physical_device->root_port;
} else {
pdev->pdev.depth = 0;
pdev->pdev.route_string = 0;
pdev->pdev.root_port = parent_port;
}
// ...
}
This function is a great place to do this logic too
i do care about msc
can you send a diff of your local fusl changes?
i dont care about nice commits
they're not done yet but sure
but it would be nice to have more code i can copy paste
and rewrite in rust
and also rewrite 10x worse
cool thanks
my xhci stuck is rust
the fact that we could share improvements to the codebase
i also am having this urge to rewrite all my code in c++
because rust is kind annoying me at this point
:O
what do you need blake3 for
and chrono i guess maybe but i dont super need it
why not just depend on https://github.com/Chocobo1/Hash or some shit
the rest are data structures (which are fine), logging (which is fine), and random utilities (which are totally doable)
no if anything id use the official blake3 shit
lol
oh wait nvm that shit uses vectors
ah true
the reference impl is pretty doable (https://github.com/BLAKE3-team/BLAKE3/tree/master/c)
i mean im using official blake3 shit already
there are two official impls of blake3
I mean if you use build.zig for your C/C++ project it's pretty nice to depend on shit
c and rust
ah kk
it's way less bad than the cmake bs
why would i use build.zig
i'd much rather port my scuffed ass rust build tool
to c++
because the zig build system is pretty good for C/C++, way better than for zig lol
it also does a bunch of shit i dont want to get rid of
like for example it deals with generating the custom debug info format i use
build.zig doesnt integrate well with go does it
you can run C/C++ code as a build step to generate it
I mean you can always shell out to it
as a build step
kinda cringe
id much rather keep shit ass go code
...
i could, but its more annoying than its worth
realistically all id need to do is generate some ninja build file and call it
and thats trivial
tbh the reason to not switch to c++ is:
(1) rust is usually quite nice
(2) rust enums are very cool
(3) i already have shitloads of pretty complex code
well 1 is invalid considering why you wanted to switch in the first place
if it's not being nice to you then who cares what it usually is
and that's why I'll never use it
I always do the funky shit
I never write normal code lol
true
but there are some nice things in rust
my favorite cursed thing is the meme i do for buffers
?
so rust has those stupid rules around mutability or whatever
like you cant have two &mut Ts or whatever
but i want to
so
i have some scuffed code that can make a &Buffer out of &mut [u8]
and the &Buffer is mutable, you can write to it
and i think it doesnt even invoke ub most of the time
anyway im now gonna try to figure out how to make async usb shit work in a way that isnt turbo pain
are transfers guaranteed to occur in order?
hmm maybe i should make an iokit-style tree instead of my shitty current tree
maybe i should make a different subsystem for dealing with usb devices
it doesnt compose well but its easyyyy
meh its fine ill just do some other random shit
that is only vaguely functional
on the same ep yes
ah cool
basically each ep is its own queue
how bad is it if i only support one queued transfer per endpoint 
for mass storage you basically have to do that anyways
it's pretty shit for ethernet adapters if you wanna do those
i do want those
so i guess i need to handle that, so, fuck
do MSC devices only stall their bulk endpoints?
I'd even say it's easier to implement ethernet adapters if you do multiple at the same time
iirc yes
for these you can just keep a ring buffer of packets, ethernet is allowed to drop or corrupt packets so you don't need any checking
it's literally a valid ethernet impl to have an unchecked ring buffer of packets to send
and to just overwrite things if you run out of space
this is what FUSL will do
i wouldnt want to trash packets ngl
dropping is fine tho
yeah fair
but that requires a conditional :^)
actually maybe that's better, could tell the host the packet got dropped
so that the caller can do things differently if it wants to
hardcode it lol
cringe
there are so many interesting bits in the hid report descriptor
why would i hardcode it
the usb implementers forum spent lots of time on it
okay so how do i hardcode it anyway
lol
nah i will try parsing HID
...
.
i'll probably end up doing some scuffed bytecoded compiler
wait the units matter?
yes
for what?
idk if you have a USB potentiometer
obviously all this needs to be part of the same spec as keyboards and mice
honestly the thing that is the most annoying is that they shoved fahrenheit as a legal unit
like fuck off
the rest are easy enough, you can just do some fixed point math to remap it to SI
bwhahahaha
the spec should explicitly say it's not
wait
whattttttttttttttttt
is it an aspirational unit?
or what the fuck are you telling me
no I'm saying that's what I think it should do
"invalid unit, use real unit"
the issue is that its not a fucking absolute unit
eh
thats probably still solvable
if i do deal with units ill definitely turn everything into SI
and ill have pixels per meter
neither is celsius :^)
good
good
if they just used degrees rankine
which is kelvin but with fahrenheit
that would be like fine
you can apply a multiple or whatever to get SI
or hear me out
make oems turn units into fucking SI
and turn it back into customary units or whatever other pain the user wants based on system locale
no way the US would impose trade restrictions on you
optimal
okay anyway
back to having fun in hid land
"fun"
hmm so i kinda got bored of reading the hid spec
does putting the device in boot mode make it do normal shit
yes
boot means it has a predefined layout
and protocol tells you if keyboard (1) or mouse (2)
modifier keys are byte 0
each bit is lctrl, lshift, lalt, lsuper, then repeated for right
second byte is unused
rest (6) of the bytes are the currently pressed scancodes
if either of those contain 0xFF the packet should be ignored, the keyboard couldn't give you the data
usually because of too many keys pressed
that's the entire protocol
for mouse you have 1 byte of buttons, lmb rmb mmb, then 2 signed bytes for x and y respectively
yeah but it cant do tablet so its useless anyway :^)
you could do parsing only for tablets
okay...
also I have no idea how to map HID tablet touchscreens to physical displays
if you figure that out then please tell me
thats why you have units lol
the panel size is in EDID
i dont have a touchscreen though
ugh but what if you have two
two what? two touchscreens?
i suspect you tell the user "well fuck u" and choose randomly
hmm my friend has a laptop with a touchscreen iirc so maybe i should ask them to dump the hid report
or maybe even two touchscreens idr
serial number?
yes i do
sure
please send
I assume you find it with some AML shit
I don't think I spotted anything like that in the HID
I mean that it doesn't look corrupt
oh yeah
what is
Both your touchpad and screen
ah
TPD0 and TPL1
see, hid parsing is so easy!
Imagine if hid bytecode was a subset of aml
lmao
why is it bad? never looked into it
its weird
its not THAT bad i guess?
the problem is that if you smushed aml into it
youd have the aml problems
hid is not really a programming language
is it turing complete?
nope
thank god lol
yes
more parsing!
had an off by one, this is corrected
this is even more correct
this is a usb tablet
actually, here is the mouse again, with an is_abs field added
and that's a usb keyboard
why is that?
its a type-length-value format
type = read_type(data)
length = read_length(data)
lookup_table[type](ctx, length)
data += length
?
would that work
eh
kinda?
how do u do it
roughly: rs loop { let item_tdat = read_item() match item_tdat.typ { 0 => handle item x(), 1 => handle item y(), } }
its two u8s iirc
yeah
let (size, typ, tag) = if ctrl == 0xfe {
// long item
let size = self.byte()?;
let tag = self.byte()?;
(size, 3, tag)
} else {
// short item
let size = ctrl & 0x3;
let typ = (ctrl >> 2) & 0x3;
let tag = ctrl >> 4;
(size, typ, tag)
};
like sub-type?
typ+tag are the type
ah
interesting
so lol
looks like an interesting format ig
aml has a similar thing for resources, there are big and small resources, and a bit tag says which one it is
and big ones might have variable layout and size, whereas small ones are mostly hardcoded
i had to invent a vm to parse them
yeah this is pretty common
static const struct uacpi_resource_convert_instruction convert_irq_to_native[] = {
OP(PACKED_ARRAY_16, AML_F(irq, irq_mask), NATIVE_F(irq, irqs),
ARG2(NATIVE_O(irq, num_irqs))),
OP(SKIP_IF_AML_SIZE_LESS_THAN, ARG0(3), IMM(6)),
OP(SET_TO_IMM, NATIVE_F(irq, length_kind),
IMM(UACPI_RESOURCE_LENGTH_KIND_FULL)),
OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, triggering), IMM(0)),
OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, polarity), IMM(3)),
OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, sharing), IMM(4)),
OP(BIT_FIELD_1, AML_F(irq, flags), NATIVE_F(irq, wake_capability), IMM(5)),
END(),
OP(SET_TO_IMM, NATIVE_F(irq, length_kind),
IMM(UACPI_RESOURCE_LENGTH_KIND_ONE_LESS)),
OP(SET_TO_IMM, NATIVE_F(irq, triggering), IMM(UACPI_TRIGGERING_EDGE)),
END(),
};

holy shit you dont have to do that much scuffed shit
have you considered writing a DSL for uacpi btw?
you have a ton of bytecode
yeah a DSL would work really well
and i feel like a proper dsl could make it somewhat more maintainable
i even considered autogenerating bytecode handlers from python
from some description lang
something for the future i guess
ACPICA is even worse, they have sparse lookup tables depending on operand type and count and switches per matching op inside each handler that do unrelated things
and obviously no microcode so everything is duplicated
some aml ops in uacpi dont even have a native handler because there's no need, and ones that do have only actual logic related stuff inside
and because of this crappy approach they still dont support some opcode combinations, like packages with expressions inside
which are used on modern real hw so acpica breaks there
@short kraken i managed to get parsing working for your touchscreen's descriptor too
oh huh there is a (3,7) entry in there
and a (0,2)
0,2 is not in the spec
i think 3,7 is broken parsing logic
anyway back to the land of things im planning to support in the near future
i.e. not digitizers
what does this mean?
its a long entry
which shouldnt happen?
or at least i didnt see the spec define it
but yeah idk
like the hid descriptor is broken?
yeah probably?
maybe linux skips unknown entries
whats the actual thing?
what thing?
that it was supposed to be
the bug?
oh i was parsing entries that were 4 bytes long as if they were 3 bytes long
lol
the entry was a "logical maximum at 2147483646" entry
which is 5 bytes total
and 4 bytes of payload
okay lets actually do something with the parse result
based
why are there 2 x/y values
multiple fingers?
there are multiple fingers at the top level
each finger has 2 x/y coords, a width and height
maybe startx endx
but it has a width/height?
no fucking clue
hmm maybe its a bug in my code actually
no it seems like two x and two y is correct
well then keep me posted on that...
it's weird
i think its just a weird display panel :^)
but that would require me to get off the shitter
lol fair
usb keyboard hid shit works
oh wait
no it doesnt
grrr
wrong byte order
ok yeah its big endain
obviously
why did they make it big endian
no fucking clue
oh also the metadata shit is little
obviously
its just the actual events that are big
i guess yeah
and they decided to byteswap everything instead of making it little endian
worst offender is iso9660
usb is little
they have both fields duplicated
ok cool anyway
and of course half the generators just generate the big endian ones incorrectly so everyone uses the little endian ones
@short kraken now i have usb hid report parsing done properly so basically im the best os
not even boot protocol damn
nope