From 13cfaa0e0d41e1b56b9e4d1c48ffc92860485b50 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 21 Jul 2025 14:11:54 +0200 Subject: [PATCH 001/144] - Changed init_stage2 from noreturn to normal function - Removed test code at the end of init_stage2 - Added call to configuration_handle in init_stage3 - Added libhcd defines - Added peripheral usb defines - Fixed dynamic link flags - Changed usb servers to link statically - Replaced early startup print in usb servers by startup print - Moved debug output in iomem dma into defined checks - Started with error response for hcd --- bolthur/server/boot/init.h | 2 +- bolthur/server/boot/init/stage2.c | 20 +-- bolthur/server/boot/init/stage3.c | 13 +- bolthur/server/platform/raspi/iomem/dma.c | 115 ++++++++++-------- bolthur/server/platform/raspi/iomem/rpc.h | 1 + bolthur/server/platform/raspi/libhcd.h | 77 ++++++++++++ bolthur/server/platform/raspi/libperipheral.h | 55 +++++++++ .../server/platform/raspi/usb/hcd/Makefile.am | 4 +- bolthur/server/platform/raspi/usb/hcd/main.c | 3 +- .../server/platform/raspi/usb/hcd/response.c | 58 +++++++++ .../server/platform/raspi/usb/hcd/response.h | 40 ++++++ .../usb/device/hid/keyboard/Makefile.am | 1 + bolthur/server/usb/device/hid/keyboard/main.c | 2 +- .../server/usb/device/hid/mouse/Makefile.am | 1 + bolthur/server/usb/device/hid/mouse/main.c | 2 +- bolthur/server/usb/device/hub/Makefile.am | 1 + bolthur/server/usb/device/hub/main.c | 2 +- bolthur/server/usb/device/storage/Makefile.am | 1 + bolthur/server/usb/device/storage/main.c | 2 +- bolthur/server/usb/usbd/Makefile.am | 1 + bolthur/server/usb/usbd/main.c | 2 +- build-aux/m4/flag.m4 | 12 +- 22 files changed, 329 insertions(+), 86 deletions(-) create mode 100644 bolthur/server/platform/raspi/libhcd.h create mode 100644 bolthur/server/platform/raspi/usb/hcd/response.c create mode 100644 bolthur/server/platform/raspi/usb/hcd/response.h diff --git a/bolthur/server/boot/init.h b/bolthur/server/boot/init.h index da34cfa9..8fc67fff 100644 --- a/bolthur/server/boot/init.h +++ b/bolthur/server/boot/init.h @@ -24,7 +24,7 @@ #include void init_stage1( void ); -[[noreturn]] void init_stage2( const char* ); +void init_stage2( const char* ); [[noreturn]] void init_stage3( void ); #endif diff --git a/bolthur/server/boot/init/stage2.c b/bolthur/server/boot/init/stage2.c index 801c5006..410a60b1 100644 --- a/bolthur/server/boot/init/stage2.c +++ b/bolthur/server/boot/init/stage2.c @@ -34,7 +34,7 @@ * @brief Stage 2 init starting necessary stuff so that stage 3 with stuff from disk can be started * @param bootarg boot arguments */ -[[noreturn]] void init_stage2( const char* bootarg ) { +void init_stage2( const char* bootarg ) { // start servers by configuration if ( ! configuration_handle( "/ramdisk/config/stage2.ini", bootarg ) ) { EARLY_STARTUP_PRINT( "Something went wrong with stage2 startup!\r\n" ) @@ -163,7 +163,7 @@ STARTUP_PRINT( "unable to set seek end: %s\r\n", strerror( errno ) ) exit( 1 ); } - size_t cmdline_size = ( size_t )position; + const size_t cmdline_size = ( size_t )position; // reset back to beginning if ( -1 == lseek( cmdline, 0, SEEK_SET ) ) { STARTUP_PRINT( "unable to set seek start: %s\r\n", strerror( errno ) ) @@ -183,20 +183,6 @@ str[ cmdline_size ] = 0; // print content STARTUP_PRINT( "str: %s\r\n", str ) + free( str ); STARTUP_PRINT( "continue with stage3!!!\r\n") - - // open dummy - FILE* fp = fopen( "/boot/cmdline.txt", "r" ); - if ( ! fp ) { - STARTUP_PRINT( "unable to open: %s\r\n", strerror( errno ) ) - exit( 1 ); - } - // fork process - pid_t boot_forked = fork(); - EARLY_STARTUP_PRINT( "error = %s\r\n", strerror( errno ) ) - EARLY_STARTUP_PRINT( "boot_forked = %d\r\n", boot_forked ) - - for (;;) { - __asm__ __volatile__ ( "nop" ); - } } diff --git a/bolthur/server/boot/init/stage3.c b/bolthur/server/boot/init/stage3.c index 7bf11888..38080041 100644 --- a/bolthur/server/boot/init/stage3.c +++ b/bolthur/server/boot/init/stage3.c @@ -23,6 +23,8 @@ #include #include #include + +#include "configuration.h" #include "../ramdisk.h" #include "../init.h" #include "../util.h" @@ -33,8 +35,17 @@ * @brief Final init stage starting servers from storage with finally starting shell */ [[noreturn]] void init_stage3( void ) { + // start servers by configuration + if ( ! configuration_handle( "/ramdisk/config/stage3.ini", nullptr ) ) { + EARLY_STARTUP_PRINT( "Something went wrong with stage3 startup!\r\n" ) + exit( 1 ); + } + + while ( true ) { + __asm__ __volatile__( "nop" ); + } + /// FIXME: Kill unnecessary ramdisk server again - /// FIXME: Start authentication manager /// FIXME: Start USB driver with all attached devices /// FIXME: Start login console diff --git a/bolthur/server/platform/raspi/iomem/dma.c b/bolthur/server/platform/raspi/iomem/dma.c index e04cd1c6..b5bbfb5e 100644 --- a/bolthur/server/platform/raspi/iomem/dma.c +++ b/bolthur/server/platform/raspi/iomem/dma.c @@ -100,7 +100,6 @@ int dma_block_prepare( void ) { * @fn int dma_block_to_phys(uintptr_t*) * @brief Translate control block to bus address * - * @param block * @param addr * @return * @@ -137,8 +136,8 @@ int dma_block_to_phys( uintptr_t* addr ) { * @todo validate parameter */ int dma_block_set_address( - uint32_t source, - uint32_t destination + const uint32_t source, + const uint32_t destination ) { if ( ! block ) { last_error = -EINVAL; @@ -156,7 +155,7 @@ int dma_block_set_address( * @param value * @return */ -int dma_block_transfer_info_source_increment( bool value ) { +int dma_block_transfer_info_source_increment( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -176,7 +175,7 @@ int dma_block_transfer_info_source_increment( bool value ) { * @param value * @return */ -int dma_block_transfer_info_destination_increment( bool value ) { +int dma_block_transfer_info_destination_increment( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -196,7 +195,7 @@ int dma_block_transfer_info_destination_increment( bool value ) { * @param value * @return */ -int dma_block_transfer_info_wait_response( bool value ) { +int dma_block_transfer_info_wait_response( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -216,7 +215,7 @@ int dma_block_transfer_info_wait_response( bool value ) { * @param value * @return */ -int dma_block_transfer_info_burst_length( uint32_t value ) { +int dma_block_transfer_info_burst_length( const uint32_t value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -232,7 +231,7 @@ int dma_block_transfer_info_burst_length( uint32_t value ) { * @param value * @return */ -int dma_block_transfer_info_src_width( bool value ) { +int dma_block_transfer_info_src_width( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -252,7 +251,7 @@ int dma_block_transfer_info_src_width( bool value ) { * @param value * @return */ -int dma_block_transfer_info_dest_width( bool value ) { +int dma_block_transfer_info_dest_width( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -272,7 +271,7 @@ int dma_block_transfer_info_dest_width( bool value ) { * @param value * @return */ -int dma_block_transfer_info_src_dreq( bool value ) { +int dma_block_transfer_info_src_dreq( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -292,7 +291,7 @@ int dma_block_transfer_info_src_dreq( bool value ) { * @param value * @return */ -int dma_block_transfer_info_dest_dreq( bool value ) { +int dma_block_transfer_info_dest_dreq( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -312,7 +311,7 @@ int dma_block_transfer_info_dest_dreq( bool value ) { * @param value * @return */ -int dma_block_transfer_info_interrupt_enable( bool value ) { +int dma_block_transfer_info_interrupt_enable( const bool value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -332,7 +331,7 @@ int dma_block_transfer_info_interrupt_enable( bool value ) { * @param value * @return */ -int dma_block_transfer_info_permap( uint32_t value ) { +int dma_block_transfer_info_permap( const uint32_t value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -349,11 +348,10 @@ int dma_block_transfer_info_permap( uint32_t value ) { * @fn int dma_block_set_transfer_length(uint32_t) * @brief Set transfer length information * - * @param block * @param value * @return */ -int dma_block_set_transfer_length( uint32_t value ) { +int dma_block_set_transfer_length( const uint32_t value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -366,11 +364,10 @@ int dma_block_set_transfer_length( uint32_t value ) { * @fn int dma_block_set_stride(uint32_t) * @brief Set stride * - * @param block * @param value * @return */ -int dma_block_set_stride( uint32_t value ) { +int dma_block_set_stride( const uint32_t value ) { if ( ! block ) { last_error = -EINVAL; return -1; @@ -399,16 +396,16 @@ int dma_block_set_next( uint32_t value ) { /** * @fn void dma_block_dump(void) * @brief Dump dma block - * - * @param block */ void dma_block_dump( void ) { - EARLY_STARTUP_PRINT( "block->destination_address: %#"PRIx32"\r\n", block->destination_address ); - EARLY_STARTUP_PRINT( "block->next_control_block: %#"PRIx32"\r\n", block->next_control_block ); - EARLY_STARTUP_PRINT( "block->source_address: %#"PRIx32"\r\n", block->source_address ); - EARLY_STARTUP_PRINT( "block->stride: %#"PRIx32"\r\n", block->stride ); - EARLY_STARTUP_PRINT( "block->transfer_information: %#"PRIx32"\r\n", block->transfer_information ); - EARLY_STARTUP_PRINT( "block->transfer_length: %#"PRIx32"\r\n", block->transfer_length ); + #if defined( DMA_ENABLE_DEBUG ) + EARLY_STARTUP_PRINT( "block->destination_address: %#"PRIx32"\r\n", block->destination_address ); + EARLY_STARTUP_PRINT( "block->next_control_block: %#"PRIx32"\r\n", block->next_control_block ); + EARLY_STARTUP_PRINT( "block->source_address: %#"PRIx32"\r\n", block->source_address ); + EARLY_STARTUP_PRINT( "block->stride: %#"PRIx32"\r\n", block->stride ); + EARLY_STARTUP_PRINT( "block->transfer_information: %#"PRIx32"\r\n", block->transfer_information ); + EARLY_STARTUP_PRINT( "block->transfer_length: %#"PRIx32"\r\n", block->transfer_length ); + #endif } /** @@ -480,8 +477,8 @@ int dma_start( void ) { */ int dma_wait( int64_t loop_max_iteration, - mmio_sleep_t sleep_type, - uint32_t sleep_value, + const mmio_sleep_t sleep_type, + const uint32_t sleep_value, void ( *apply_sleep )( mmio_sleep_t, uint32_t ) ) { if ( ! block ) { @@ -506,18 +503,24 @@ int dma_wait( // handle possible error if ( value & LIBDMA_CS_ERROR ) { // query debug register of dma channel - uint32_t debug = mmio_read( PERIPHERAL_DMA0_DEBUG ); + const uint32_t debug = mmio_read( PERIPHERAL_DMA0_DEBUG ); // check for read error if ( debug & LIBDMA_DEBUG_READ_ERROR ) { - EARLY_STARTUP_PRINT( "ERROR WHILE READING!\r\n" ); + #if defined( DMA_ENABLE_DEBUG ) + EARLY_STARTUP_PRINT( "ERROR WHILE READING!\r\n" ); + #endif } // check for fifo error if ( debug & LIBDMA_DEBUG_FIFO_ERROR ) { - EARLY_STARTUP_PRINT( "FIFO ERROR!\r\n" ) + #if defined( DMA_ENABLE_DEBUG ) + EARLY_STARTUP_PRINT( "FIFO ERROR!\r\n" ) + #endif } // check for read last not set error if ( debug & LIBDMA_DEBUG_READ_LAST_NOT_SET_ERROR ) { - EARLY_STARTUP_PRINT( "READ LAST NOT SET ERROR\r\n" ); + #if defined( DMA_ENABLE_DEBUG ) + EARLY_STARTUP_PRINT( "READ LAST NOT SET ERROR\r\n" ); + #endif } // dump everything dma_dump(); @@ -525,7 +528,9 @@ int dma_wait( return -1; } if ( value & LIBDMA_CS_INT ) { - EARLY_STARTUP_PRINT( "INTERRUPT PENDING!\r\n" ); + #if defined( DMA_ENABLE_DEBUG ) + EARLY_STARTUP_PRINT( "INTERRUPT PENDING!\r\n" ); + #endif } // apply possible sleep if ( ! ( value & LIBDMA_CS_END ) ) { @@ -564,28 +569,30 @@ int dma_finish( void ) { * @brief Dump dma registers */ void dma_dump( void ) { - uint32_t value = mmio_read( PERIPHERAL_DMA0_CS ); - EARLY_STARTUP_PRINT( "CS: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_CONBLK_AD ); - EARLY_STARTUP_PRINT( "CONBLK_AD: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_TI ); - EARLY_STARTUP_PRINT( "TI: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_SOURCE_AD ); - EARLY_STARTUP_PRINT( "SOURCE_AD: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_DEST_AD ); - EARLY_STARTUP_PRINT( "DEST_AD: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_TXFR_LEN ); - EARLY_STARTUP_PRINT( "TXFR_LEN: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_STRIDE ); - EARLY_STARTUP_PRINT( "STRIDE: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_NEXTCONBK ); - EARLY_STARTUP_PRINT( "NEXTCONBK: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA0_DEBUG ); - EARLY_STARTUP_PRINT( "DEBUG: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA_INT_STATUS ); - EARLY_STARTUP_PRINT( "INT_STATUS: %#"PRIx32"\r\n", value ); - value = mmio_read( PERIPHERAL_DMA_ENABLE ); - EARLY_STARTUP_PRINT( "ENABLE: %#"PRIx32"\r\n", value ); + #if defined( DMA_ENABLE_DEBUG ) + uint32_t value = mmio_read( PERIPHERAL_DMA0_CS ); + EARLY_STARTUP_PRINT( "CS: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_CONBLK_AD ); + EARLY_STARTUP_PRINT( "CONBLK_AD: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_TI ); + EARLY_STARTUP_PRINT( "TI: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_SOURCE_AD ); + EARLY_STARTUP_PRINT( "SOURCE_AD: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_DEST_AD ); + EARLY_STARTUP_PRINT( "DEST_AD: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_TXFR_LEN ); + EARLY_STARTUP_PRINT( "TXFR_LEN: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_STRIDE ); + EARLY_STARTUP_PRINT( "STRIDE: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_NEXTCONBK ); + EARLY_STARTUP_PRINT( "NEXTCONBK: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA0_DEBUG ); + EARLY_STARTUP_PRINT( "DEBUG: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA_INT_STATUS ); + EARLY_STARTUP_PRINT( "INT_STATUS: %#"PRIx32"\r\n", value ); + value = mmio_read( PERIPHERAL_DMA_ENABLE ); + EARLY_STARTUP_PRINT( "ENABLE: %#"PRIx32"\r\n", value ); + #endif } /** diff --git a/bolthur/server/platform/raspi/iomem/rpc.h b/bolthur/server/platform/raspi/iomem/rpc.h index ca101430..5b25f9e1 100644 --- a/bolthur/server/platform/raspi/iomem/rpc.h +++ b/bolthur/server/platform/raspi/iomem/rpc.h @@ -25,6 +25,7 @@ #include //#define RPC_ENABLE_DEBUG 1 +//#define DMA_ENABLE_DEBUG 1 bool rpc_init( void ); void rpc_handle_ioctl( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/platform/raspi/libhcd.h b/bolthur/server/platform/raspi/libhcd.h new file mode 100644 index 00000000..3127c811 --- /dev/null +++ b/bolthur/server/platform/raspi/libhcd.h @@ -0,0 +1,77 @@ +/** +* Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIBHCD_H +#define _LIBHCD_H + +// interrupt +#define ARM_IRQ_USB 9 + +// core interrupts +#define HCD_CORE_INTERRUPT_CURRENT_MODE ( 1 << 0 ) +#define HCD_CORE_INTERRUPT_MODE_MISMATCH ( 1 << 1 ) +#define HCD_CORE_INTERRUPT_OTG ( 1 << 2 ) +#define HCD_CORE_INTERRUPT_DMA_START_OF_FRAME ( 1 << 3 ) +#define HCD_CORE_INTERRUPT_RECEIVE_STATUS_LEVEL ( 1 << 4 ) +#define HCD_CORE_INTERRUPT_NP_TRANSMIT_FIFO_EMPTY ( 1 << 5 ) +#define HCD_CORE_INTERRUPT_GINNAKEFF ( 1 << 6 ) +#define HCD_CORE_INTERRUPT_GOUTNAKEFF ( 1 << 7 ) +#define HCD_CORE_INTERRUPT_ULPICK ( 1 << 8 ) +#define HCD_CORE_INTERRUPT_I2C ( 1 << 9 ) +#define HCD_CORE_INTERRUPT_EARLY_SUSPEND ( 1 << 10 ) +#define HCD_CORE_INTERRUPT_USB_SUSPEND ( 1 << 11 ) +#define HCD_CORE_INTERRUPT_USB_RESET ( 1 << 12 ) +#define HCD_CORE_INTERRUPT_ENUMARTION_DONE ( 1 << 13 ) +#define HCD_CORE_INTERRUPT_ISOCHRONOUS_OUT_DROP ( 1 << 14 ) +#define HCD_CORE_INTERRUPT_EOPFRAME ( 1 << 15 ) +#define HCD_CORE_INTERRUPT_RESTORE_DONE ( 1 << 16 ) +#define HCD_CORE_INTERRUPT_END_POINT_MISMATCH ( 1 << 17 ) +#define HCD_CORE_INTERRUPT_IN_END_POINT ( 1 << 18 ) +#define HCD_CORE_INTERRUPT_OUT_END_POINT ( 1 << 19 ) +#define HCD_CORE_INTERRUPT_INCOMPLETE_ISOCHRONOUS_IN ( 1 << 20 ) +#define HCD_CORE_INTERRUPT_INCOMPLETE_ISOCHRONOUS_OUT ( 1 << 21 ) +#define HCD_CORE_INTERRUPT_FETSETUP ( 1 << 22 ) +#define HCD_CORE_INTERRUPT_RESET_DETECT ( 1 << 23 ) +#define HCD_CORE_INTERRUPT_PORT ( 1 << 24 ) +#define HCD_CORE_INTERRUPT_HOST_CHANNEL ( 1 << 25 ) +#define HCD_CORE_INTERRUPT_HP_TRANSMIT_FIFO_EMPTY ( 1 << 26 ) +#define HCD_CORE_INTERRUPT_LOW_POWER_MODE_TRANSMIT_RECEIVED ( 1 << 27 ) +#define HCD_CORE_INTERRUPT_CONNECTION_ID_STATUS_CHANGE ( 1 << 28 ) +#define HCD_CORE_INTERRUPT_DISCONNECT ( 1 << 29 ) +#define HCD_CORE_INTERRUPT_SESSION_REQUEST ( 1 << 30 ) +#define HCD_CORE_INTERRUPT_WAKEUP ( 1 << 31 ) + +// channel interrupts +#define HCD_CHANNEL_INTERRUPT_TRANSFER_COMPLETE ( 1 << 0 ) +#define HCD_CHANNEL_INTERRUPT_HALT ( 1 << 1 ) +#define HCD_CHANNEL_INTERRUPT_AHB_ERROR ( 1 << 2 ) +#define HCD_CHANNEL_INTERRUPT_STALL ( 1 << 3 ) +#define HCD_CHANNEL_INTERRUPT_NEGATIVE_ACKNOWLEDGEMENT ( 1 << 4 ) +#define HCD_CHANNEL_INTERRUPT_ACKNOWLEDGEMENT ( 1 << 5 ) +#define HCD_CHANNEL_INTERRUPT_NOT_YET ( 1 << 6 ) +#define HCD_CHANNEL_INTERRUPT_TRANSACTION_ERROR ( 1 << 7 ) +#define HCD_CHANNEL_INTERRUPT_BABBLE_ERROR ( 1 << 8 ) +#define HCD_CHANNEL_INTERRUPT_FRAME_OVERRUN ( 1 << 9 ) +#define HCD_CHANNEL_INTERRUPT_DATA_TOGGLE_ERROR ( 1 << 10 ) +#define HCD_CHANNEL_INTERRUPT_BUFFER_NOT_AVAILABLE ( 1 << 11 ) +#define HCD_CHANNEL_INTERRUPT_EXCESSIVE_TRANSMISSION ( 1 << 12 ) +#define HCD_CHANNEL_INTERRUPT_FRAME_LIST_ROLLOVER ( 1 << 13 ) +#define HCD_CHANNEL_INTERRUPT_RESERVED 0xffffc000 + +#endif diff --git a/bolthur/server/platform/raspi/libperipheral.h b/bolthur/server/platform/raspi/libperipheral.h index 5df05d6f..da1a952b 100644 --- a/bolthur/server/platform/raspi/libperipheral.h +++ b/bolthur/server/platform/raspi/libperipheral.h @@ -276,5 +276,60 @@ #define PERIPHERAL_EMMC_SLOTISR_VER PERIPHERAL_EMMC_OFFSET + 0xFC // slot interrupt status and version // usb #define PERIPHERAL_USB_OFFSET 0x980000 +#define PERIPHERAL_USB_CORE_OFFSET PERIPHERAL_USB_OFFSET +#define PERIPHERAL_USB_HOST_OFFSET PERIPHERAL_USB_OFFSET + 0x400 +#define PERIPHERAL_USB_POWER_OFFSET PERIPHERAL_USB_OFFSET + 0xE00 +// dwhci core +#define PERIPHERAL_DWHCI_CORE_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x000 +#define PERIPHERAL_DWHCI_CORE_OTG_INIT PERIPHERAL_USB_CORE_OFFSET + 0x004 +#define PERIPHERAL_DWHCI_CORE_AHB_CFG PERIPHERAL_USB_CORE_OFFSET + 0x008 +#define PERIPHERAL_DWHCI_CORE_USB_CFG PERIPHERAL_USB_CORE_OFFSET + 0x00C +#define PERIPHERAL_DWHCI_CORE_RESET PERIPHERAL_USB_CORE_OFFSET + 0x010 +#define PERIPHERAL_DWHCI_CORE_INT_STAT PERIPHERAL_USB_CORE_OFFSET + 0x014 +#define PERIPHERAL_DWHCI_CORE_INT_MASK PERIPHERAL_USB_CORE_OFFSET + 0x018 +#define PERIPHERAL_DWHCI_CORE_RX_STAT_RD PERIPHERAL_USB_CORE_OFFSET + 0x01C +#define PERIPHERAL_DWHCI_CORE_RX_STAT_POP PERIPHERAL_USB_CORE_OFFSET + 0x020 +#define PERIPHERAL_DWHCI_CORE_RX_FIFO_SIZ PERIPHERAL_USB_CORE_OFFSET + 0x024 +#define PERIPHERAL_DWHCI_CORE_NPER_FIFO_SIZ PERIPHERAL_USB_CORE_OFFSET + 0x028 +#define PERIPHERAL_DWHCI_CORE_NPER_TX_STAT PERIPHERAL_USB_CORE_OFFSET + 0x02C +#define PERIPHERAL_DWHCI_CORE_I2C_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x030 +#define PERIPHERAL_DWHCI_CORE_PHY_VENDOR_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x034 +#define PERIPHERAL_DWHCI_CORE_GPIO PERIPHERAL_USB_CORE_OFFSET + 0x038 +#define PERIPHERAL_DWHCI_CORE_USER_ID PERIPHERAL_USB_CORE_OFFSET + 0x03C +#define PERIPHERAL_DWHCI_CORE_VENDOR_ID PERIPHERAL_USB_CORE_OFFSET + 0x040 +#define PERIPHERAL_DWHCI_CORE_HW_CFG1 PERIPHERAL_USB_CORE_OFFSET + 0x044 +#define PERIPHERAL_DWHCI_CORE_HW_CFG2 PERIPHERAL_USB_CORE_OFFSET + 0x048 +#define PERIPHERAL_DWHCI_CORE_HW_CFG3 PERIPHERAL_USB_CORE_OFFSET + 0x04C +#define PERIPHERAL_DWHCI_CORE_HW_CFG4 PERIPHERAL_USB_CORE_OFFSET + 0x050 +#define PERIPHERAL_DWHCI_CORE_LPM_CFG PERIPHERAL_USB_CORE_OFFSET + 0x054 +#define PERIPHERAL_DWHCI_CORE_POWER_DOWN PERIPHERAL_USB_CORE_OFFSET + 0x058 +#define PERIPHERAL_DWHCI_CORE_DFIFO_CFG PERIPHERAL_USB_CORE_OFFSET + 0x05C +#define PERIPHERAL_DWHCI_CORE_ADP_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x060 +#define PERIPHERAL_DWHCI_CORE_MDIO_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x080 +#define PERIPHERAL_DWHCI_CORE_MDIO_DATA PERIPHERAL_USB_CORE_OFFSET + 0x084 +#define PERIPHERAL_DWHCI_CORE_VBUS_DRV_CTRL PERIPHERAL_USB_CORE_OFFSET + 0x088 +#define PERIPHERAL_DWHCI_CORE_HOST_PER_TX_FIFO_SZ PERIPHERAL_USB_CORE_OFFSET + 0x100 +#define PERIPHERAL_DWHCI_CORE_DEV_PER_TX_FIFO( fifo ) ( PERIPHERAL_USB_CORE_OFFSET + 0x104 + ( fifo ) * 4 ) +#define PERIPHERAL_DWHCI_CORE_DEV_TX_FIFO( fifo ) ( PERIPHERAL_USB_CORE_OFFSET + 0x108 + ( fifo ) * 4 ) +// dwhci host +#define PERIPHERAL_DWHCI_HOST_CFG PERIPHERAL_USB_HOST_OFFSET + 0x000 +#define PERIPHERAL_DWHCI_HOST_FRM_INTERVAL PERIPHERAL_USB_HOST_OFFSET + 0x004 +#define PERIPHERAL_DWHCI_HOST_FRM_NUM PERIPHERAL_USB_HOST_OFFSET + 0x008 +#define PERIPHERAL_DWHCI_HOST_PER_TX_FIFO_STAT PERIPHERAL_USB_HOST_OFFSET + 0x010 +#define PERIPHERAL_DWHCI_HOST_ALLCHAN_INT PERIPHERAL_USB_HOST_OFFSET + 0x014 +#define PERIPHERAL_DWHCI_HOST_ALLCHAN_INT_MASK PERIPHERAL_USB_HOST_OFFSET + 0x018 +#define PERIPHERAL_DWHCI_HOST_FRMLST_BASE PERIPHERAL_USB_HOST_OFFSET + 0x01C +#define PERIPHERAL_DWHCI_HOST_PORT PERIPHERAL_USB_HOST_OFFSET + 0x040 +#define PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x100 + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x104 + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_CHAN_INT( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x108 + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_CHAN_INT_MASK( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x10C + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x110 + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_HOST_CHAN_DMA_ADDR( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x114 + ( chan ) * 0x20 ) +#define PERIPHERAL_DWHCI_HOST_HOST_CHAN_DMA_BUF( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x11C + ( chan ) * 0x20 ) +// dwhci data fifo ( non dma only ) +#define PERIPHERAL_DWHCI_DATA_FIFO_SIZE 0x1000 +#define PERIPHERAL_DWHCI_MAX_CHANNELS 16 +#define PERIPHERAL_DWHCI_DATA_FIFO( chan ) ( PERIPHERAL_USB_HOST_OFFSET + 0x1000 + ( chan ) * PERIPHERAL_DWHCI_DATA_FIFO_SIZE ) #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/Makefile.am b/bolthur/server/platform/raspi/usb/hcd/Makefile.am index dfc8f2e8..45b73c60 100644 --- a/bolthur/server/platform/raspi/usb/hcd/Makefile.am +++ b/bolthur/server/platform/raspi/usb/hcd/Makefile.am @@ -3,4 +3,6 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/hcd\" bin_PROGRAMS = hcd hcd_SOURCES = \ - main.c + main.c \ + response.c +hcd_LDFLAGS = -all-static --static diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index 0226eb36..e77b66ad 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -19,6 +19,7 @@ #include #include +#include "../../libperipheral.h" /** * @fn int main(int, char*[]) @@ -30,6 +31,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usb hcd processing!\r\n" ) + STARTUP_PRINT( "usb hcd processing!\r\n" ) return -1; } diff --git a/bolthur/server/platform/raspi/usb/hcd/response.c b/bolthur/server/platform/raspi/usb/hcd/response.c new file mode 100644 index 00000000..cced6efe --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/response.c @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "response.h" + +static response_message_entry_t response_error_message[] = { + { "OK" }, + { "Memory error" }, + { "I/O error" }, + { "Mailbox error" }, + { "Not implemented" }, + { "Timeout while waiting for completion" }, + { "Unknown error" }, + { "Driver incompatible" }, +}; + +/** + * @fn const char* response_error(response_t) + * @brief Method to translate response to error + * @param num response to translate + * @return translated error + */ +const char* response_error( response_t num ) { + // static buffer + static char buffer[ 1024 ]; + // set total length to length - 1 to leave space for 0 termination + constexpr size_t total_length = sizeof( buffer ) - 1; + // clear buffer + memset( buffer, 0, sizeof( buffer ) ); + // determine entry count + constexpr size_t error_count = sizeof( response_error_message ) + / sizeof( response_message_entry_t ); + // handle invalid error code + if ( num >= error_count ) { + return nullptr; + } + // push message string to buffer + strncpy( buffer, response_error_message[ num ].message, total_length ); + // return buffer + return buffer; +} diff --git a/bolthur/server/platform/raspi/usb/hcd/response.h b/bolthur/server/platform/raspi/usb/hcd/response.h new file mode 100644 index 00000000..28188e81 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/response.h @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RESPONSE_H +#define _RESPONSE_H + +typedef enum{ + HCD_RESPONSE_OK = 0, + HCD_RESPONSE_ERROR_MEMORY, + HCD_RESPONSE_ERROR_IO, + HCD_RESPONSE_ERROR_MAILBOX, + HCD_RESPONSE_ERROR_NOT_IMPLEMENTED, + HCD_RESPONSE_ERROR_TIMEOUT, + HCD_RESPONSE_ERROR_UNKNOWN, + HCD_RESPONSE_ERROR_INCOMPATIBLE, +} response_t; + +typedef struct { + char* message; +} response_message_entry_t; + +const char* response_error( response_t ); + +#endif //_RESPONSE_H diff --git a/bolthur/server/usb/device/hid/keyboard/Makefile.am b/bolthur/server/usb/device/hid/keyboard/Makefile.am index b1b70087..e6f16990 100644 --- a/bolthur/server/usb/device/hid/keyboard/Makefile.am +++ b/bolthur/server/usb/device/hid/keyboard/Makefile.am @@ -4,3 +4,4 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/keyboard\" bin_PROGRAMS = keyboard keyboard_SOURCES = \ main.c +keyboard_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/keyboard/main.c b/bolthur/server/usb/device/hid/keyboard/main.c index 5d12e4b1..dfd3ab70 100644 --- a/bolthur/server/usb/device/hid/keyboard/main.c +++ b/bolthur/server/usb/device/hid/keyboard/main.c @@ -30,6 +30,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usb hid keyboard processing!\r\n" ) + STARTUP_PRINT( "usb hid keyboard processing!\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/hid/mouse/Makefile.am b/bolthur/server/usb/device/hid/mouse/Makefile.am index 382fe8bd..80717fee 100644 --- a/bolthur/server/usb/device/hid/mouse/Makefile.am +++ b/bolthur/server/usb/device/hid/mouse/Makefile.am @@ -4,3 +4,4 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/mouse\" bin_PROGRAMS = mouse mouse_SOURCES = \ main.c +mouse_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/mouse/main.c b/bolthur/server/usb/device/hid/mouse/main.c index a130b3c3..114d6f66 100644 --- a/bolthur/server/usb/device/hid/mouse/main.c +++ b/bolthur/server/usb/device/hid/mouse/main.c @@ -30,6 +30,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usb hid mouse processing!\r\n" ) + STARTUP_PRINT( "usb hid mouse processing!\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index 1067dafb..21c0c17a 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -4,3 +4,4 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hub\" bin_PROGRAMS = hub hub_SOURCES = \ main.c +hub_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 3b01cc85..bff12006 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -30,6 +30,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usb hub processing!\r\n" ) + STARTUP_PRINT( "usb hub processing!\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/storage/Makefile.am b/bolthur/server/usb/device/storage/Makefile.am index 9182afc4..379fee4a 100644 --- a/bolthur/server/usb/device/storage/Makefile.am +++ b/bolthur/server/usb/device/storage/Makefile.am @@ -4,3 +4,4 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/storage\" bin_PROGRAMS = storage storage_SOURCES = \ main.c +storage_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/storage/main.c b/bolthur/server/usb/device/storage/main.c index aed8565b..58b32394 100644 --- a/bolthur/server/usb/device/storage/main.c +++ b/bolthur/server/usb/device/storage/main.c @@ -30,6 +30,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usb storage processing!\r\n" ) + STARTUP_PRINT( "usb storage processing!\r\n" ) return -1; } diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index 6c78c4ba..30a03a44 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -4,3 +4,4 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/usbd\" bin_PROGRAMS = usbd usbd_SOURCES = \ main.c +usbd_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index 3a5d58bf..3bf88504 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -30,6 +30,6 @@ */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // print something - EARLY_STARTUP_PRINT( "usbd processing!\r\n" ) + STARTUP_PRINT( "usbd processing!\r\n" ) return -1; } diff --git a/build-aux/m4/flag.m4 b/build-aux/m4/flag.m4 index ddd667d6..a74df6f4 100644 --- a/build-aux/m4/flag.m4 +++ b/build-aux/m4/flag.m4 @@ -32,8 +32,8 @@ AC_DEFUN([BOLTHUR_LIBRARY_SET_FLAG], [ #AC_DEFINE_UNQUOTED([_FORTIFY_SOURCE], [2], [Necessary newlib define]) # linker flags - AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/ramdisk/usr/lib/ld-bolthur.so]) - AX_APPEND_LINK_FLAGS([-Wl,-rpath=/ramdisk/lib,--enable-new-dtags]) + AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/usr/lib/ld-bolthur.so]) + AX_APPEND_LINK_FLAGS([-Wl,-rpath=/usr/lib,--enable-new-dtags]) # custom optimization level AS_IF([test "x$enable_release" != "xyes"], [ @@ -189,8 +189,8 @@ AC_DEFUN([BOLTHUR_SERVER_SET_FLAG], [ #AC_DEFINE_UNQUOTED([_FORTIFY_SOURCE], [2], [Necessary newlib define]) # linker flags - AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/ramdisk/usr/lib/ld-bolthur.so]) - AX_APPEND_LINK_FLAGS([-Wl,-rpath=/ramdisk/lib,--enable-new-dtags]) + AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/usr/lib/ld-bolthur.so]) + AX_APPEND_LINK_FLAGS([-Wl,-rpath=/usr/lib,--enable-new-dtags]) # custom optimization level AS_IF([test "x$enable_release" != "xyes"], [ @@ -260,8 +260,8 @@ AC_DEFUN([BOLTHUR_APPLICATION_SET_FLAG], [ #AC_DEFINE_UNQUOTED([_FORTIFY_SOURCE], [2], [Necessary newlib define]) # linker flags - AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/ramdisk/usr/lib/ld-bolthur.so]) - AX_APPEND_LINK_FLAGS([-Wl,-rpath=/ramdisk/lib,--enable-new-dtags]) + AX_APPEND_LINK_FLAGS([-Wl,--dynamic-linker=/usr/lib/ld-bolthur.so]) + AX_APPEND_LINK_FLAGS([-Wl,-rpath=/usr/lib,--enable-new-dtags]) # custom optimization level AS_IF([test "x$enable_release" != "xyes"], [ From e2e28691b6b1cd8371f1a687c76065e9e82ed696 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 21 Jul 2025 14:49:27 +0200 Subject: [PATCH 002/144] - Ported bunch of util functions from sd server to hcd server - Extended response enum by einval - Added call to dwhci_init within main - Created dwhci init and query vendor --- .../server/platform/raspi/usb/hcd/Makefile.am | 4 +- bolthur/server/platform/raspi/usb/hcd/dwhci.c | 149 ++++++++++++++++++ bolthur/server/platform/raspi/usb/hcd/dwhci.h | 31 ++++ bolthur/server/platform/raspi/usb/hcd/main.c | 19 ++- .../server/platform/raspi/usb/hcd/response.c | 1 + .../server/platform/raspi/usb/hcd/response.h | 1 + bolthur/server/platform/raspi/usb/hcd/util.c | 83 ++++++++++ bolthur/server/platform/raspi/usb/hcd/util.h | 28 ++++ 8 files changed, 313 insertions(+), 3 deletions(-) create mode 100644 bolthur/server/platform/raspi/usb/hcd/dwhci.c create mode 100644 bolthur/server/platform/raspi/usb/hcd/dwhci.h create mode 100644 bolthur/server/platform/raspi/usb/hcd/util.c create mode 100644 bolthur/server/platform/raspi/usb/hcd/util.h diff --git a/bolthur/server/platform/raspi/usb/hcd/Makefile.am b/bolthur/server/platform/raspi/usb/hcd/Makefile.am index 45b73c60..e8677f45 100644 --- a/bolthur/server/platform/raspi/usb/hcd/Makefile.am +++ b/bolthur/server/platform/raspi/usb/hcd/Makefile.am @@ -3,6 +3,8 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/hcd\" bin_PROGRAMS = hcd hcd_SOURCES = \ + dwhci.c \ main.c \ - response.c + response.c \ + util.c hcd_LDFLAGS = -all-static --static diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c new file mode 100644 index 00000000..243af1a5 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -0,0 +1,149 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +// local includes +#include "dwhci.h" +#include "util.h" +#include "response.h" +// driver includes +#include + +#include "../../libiomem.h" +#include "../../libperipheral.h" + +/** + * @brief Static file descriptor for iomem operations + */ +static int fd_iomem = -1; + +/** + * @fn uint32_t dwhci_query_vendor(uint32_t*) + * @brief Helper to query vendor + * @param destination pointer to write vendor id to + * @return operation response + */ +response_t dwhci_query_vendor( uint32_t* destination ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Query vendor information\r\n" ) + #endif + // validate parameter + if ( ! destination ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Invalid parameters passed!\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_EINVAL; + } + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // overwrite register to read + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_VENDOR_ID; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Mark interrupt as handled sequence failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_IO; + } + // push read value into destination + *destination = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_init(void) + * @brief Init dwhci + * @return init response + */ +response_t dwhci_init( void ) { + // open file descriptor for mmio actions + if ( -1 == ( fd_iomem = open( IOMEM_DEVICE_PATH, O_RDWR ) ) ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to open device\r\n" ) + #endif + // return error response + return HCD_RESPONSE_ERROR_IO; + } + // query vendor id + uint32_t vendor; + response_t result = dwhci_query_vendor( &vendor ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Query vendor information failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( + "HCD: Hardware: %c%c%"PRIx32".%"PRIx32"%"PRIx32"%"PRIx32"\r\n", + ( char )( vendor >> 24 & 0xff ), + ( char )( vendor >> 16 & 0xff ), + vendor >> 12 & 0xf, + vendor >> 8 & 0xf, + vendor >> 4 & 0xf, + vendor >> 0 & 0xf + ) + #endif + // check fetched vendor + if ( ( vendor & 0xfffff000 ) != 0x4F542000 ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "HCD: Driver incompatible\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_INCOMPATIBLE; + } + /// FIXME: CONTINUE HCD INIT + // return success + return HCD_RESPONSE_OK; +} diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h new file mode 100644 index 00000000..9b2cee6e --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _DWHCI_H +#define _DWHCI_H + +#include +#include "response.h" + +#define DWHCI_ENABLE_DEBUG 1 + +response_t dwhci_query_vendor( uint32_t* destination ); +response_t dwhci_init( void ); + +#endif //_DWHCI_H diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index e77b66ad..c2286d13 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -19,6 +19,9 @@ #include #include + +#include "dwhci.h" +#include "response.h" #include "../../libperipheral.h" /** @@ -30,7 +33,19 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print something - STARTUP_PRINT( "usb hcd processing!\r\n" ) + // print starting + STARTUP_PRINT( "Setup hcd interface!\r\n" ) + + // init dwhci + const response_t result = dwhci_init(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + STARTUP_PRINT( "Unable to init dwhci: %s\r\n", response_error( result ) ); + return -1; + } + + while ( true ) { + __asm__ __volatile__ ( "nop" ); + } return -1; } diff --git a/bolthur/server/platform/raspi/usb/hcd/response.c b/bolthur/server/platform/raspi/usb/hcd/response.c index cced6efe..9cf30aa9 100644 --- a/bolthur/server/platform/raspi/usb/hcd/response.c +++ b/bolthur/server/platform/raspi/usb/hcd/response.c @@ -25,6 +25,7 @@ static response_message_entry_t response_error_message[] = { { "Memory error" }, { "I/O error" }, { "Mailbox error" }, + { "Invalid arguments" }, { "Not implemented" }, { "Timeout while waiting for completion" }, { "Unknown error" }, diff --git a/bolthur/server/platform/raspi/usb/hcd/response.h b/bolthur/server/platform/raspi/usb/hcd/response.h index 28188e81..d889249a 100644 --- a/bolthur/server/platform/raspi/usb/hcd/response.h +++ b/bolthur/server/platform/raspi/usb/hcd/response.h @@ -25,6 +25,7 @@ typedef enum{ HCD_RESPONSE_ERROR_MEMORY, HCD_RESPONSE_ERROR_IO, HCD_RESPONSE_ERROR_MAILBOX, + HCD_RESPONSE_ERROR_EINVAL, HCD_RESPONSE_ERROR_NOT_IMPLEMENTED, HCD_RESPONSE_ERROR_TIMEOUT, HCD_RESPONSE_ERROR_UNKNOWN, diff --git a/bolthur/server/platform/raspi/usb/hcd/util.c b/bolthur/server/platform/raspi/usb/hcd/util.c new file mode 100644 index 00000000..8495dbfa --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/util.c @@ -0,0 +1,83 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// local includes +#include "util.h" +// driver includes +#include "../../libiomem.h" + +/** + * @fn void util_prepare_mmio_sequence*(size_t, size_t*) + * @brief Prepare mmio sequence + * + * @param count + * @param total + */ +void* util_prepare_mmio_sequence( const size_t count, size_t* total ) { + if ( 0 == count ) { + return NULL; + } + // allocate + const size_t tmp_total = count * sizeof( iomem_mmio_entry_t ); + iomem_mmio_entry_t* tmp = malloc( count * sizeof( iomem_mmio_entry_t ) ); + if ( ! tmp ) { + return NULL; + } + // erase + memset( tmp, 0, tmp_total ); + // preset with defaults + for ( uint32_t i = 0; i < count; i++ ) { + tmp[ i ].shift_type = IOMEM_MMIO_SHIFT_NONE; + tmp[ i ].sleep_type = IOMEM_MMIO_SLEEP_NONE; + tmp[ i ].failure_condition = IOMEM_MMIO_FAILURE_CONDITION_OFF; + } + // set total if not null + if ( total ) { + *total = tmp_total; + } + // return + return tmp; +} + +/** + * @fn void* util_prepare_mailbox*(size_t, size_t*) + * @brief Helper to allocate and clear mailbox property array + * + * @param count + * @param total + */ +void* util_prepare_mailbox( const size_t count, size_t* total ) { + if ( 0 == count ) { + return NULL; + } + // allocate + const size_t tmp_total = count * sizeof( uint32_t ); + iomem_mmio_entry_t* tmp = malloc( tmp_total ); + if ( ! tmp ) { + return NULL; + } + // erase + memset( tmp, 0, tmp_total ); + // set total if not null + if ( total ) { + *total = tmp_total; + } + // return + return tmp; +} diff --git a/bolthur/server/platform/raspi/usb/hcd/util.h b/bolthur/server/platform/raspi/usb/hcd/util.h new file mode 100644 index 00000000..c6d867a8 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/util.h @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include + +void* util_prepare_mmio_sequence( size_t, size_t* ); +void* util_prepare_mailbox( size_t, size_t* ); + +#endif //_UTIL_H From a1206222fa96c613ca4970b5442f7b833d2c735b Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 21 Jul 2025 16:50:21 +0200 Subject: [PATCH 003/144] - Replaced hardcoded 0 in emmc by define - Added function to power on usb device - Added call to power on usb device in dwhci init - Added rpc init and rpc handle interrupt to dwhci - Added bind of interrupt within rpc init - Added call to rpc init before setup of hcd interface - Added function to disable and enable interrupts - Added empty functions to init core and init host - Replaced magic interrupt numbers by defines - Added whitelist of usb interrupt to raspi target in kernel --- bolthur/kernel/platform/raspi/interrupt.c | 17 +- bolthur/kernel/platform/raspi/interrupt.h | 41 ++ bolthur/kernel/platform/raspi/serial.c | 5 +- bolthur/kernel/syscall/interrupt.c | 6 +- bolthur/server/platform/raspi/libhcd.h | 8 + .../server/platform/raspi/storage/sd/emmc.c | 2 +- .../server/platform/raspi/usb/hcd/Makefile.am | 2 + bolthur/server/platform/raspi/usb/hcd/dwhci.c | 349 +++++++++++++++++- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 6 + bolthur/server/platform/raspi/usb/hcd/main.c | 19 +- bolthur/server/platform/raspi/usb/hcd/rpc.h | 29 ++ .../server/platform/raspi/usb/hcd/rpc/init.c | 41 ++ .../raspi/usb/hcd/rpc/interrupt/handle.c | 37 ++ 13 files changed, 537 insertions(+), 25 deletions(-) create mode 100644 bolthur/kernel/platform/raspi/interrupt.h create mode 100644 bolthur/server/platform/raspi/usb/hcd/rpc.h create mode 100644 bolthur/server/platform/raspi/usb/hcd/rpc/init.c create mode 100644 bolthur/server/platform/raspi/usb/hcd/rpc/interrupt/handle.c diff --git a/bolthur/kernel/platform/raspi/interrupt.c b/bolthur/kernel/platform/raspi/interrupt.c index 3174e72d..3402d9cd 100644 --- a/bolthur/kernel/platform/raspi/interrupt.c +++ b/bolthur/kernel/platform/raspi/interrupt.c @@ -24,6 +24,7 @@ #include "gpio.h" #include "peripheral.h" #include "../../debug/debug.h" +#include "interrupt.h" /** * @fn bool interrupt_validate_number(size_t) @@ -35,14 +36,14 @@ */ bool interrupt_validate_number( const size_t num ) { return ! ( - num != 1 && num != 8 - && num != 29 && num != 43 - && num != 45 && num != 46 - && num != 48 && num != 49 - && num != 50 && num != 51 - && num != 52 && num != 53 - && num != 54 && num != 55 - && num != 57 + num != IRQ_MAILBOX && num != 8 + && num != IRQ_USB && num != IRQ_AUX + && num != IRQ_I2C_SPI && num != IRQ_PWA0 + && num != IRQ_PWA1 && num != IRQ_SMI + && num != IRQ_GPIO0 && num != IRQ_GPIO1 + && num != IRQ_GPIO2 && num != IRQ_GPIO3 + && num != IRQ_I2C && num != IRQ_SPI + && num != IRQ_PCM && num != IRQ_UART ); } diff --git a/bolthur/kernel/platform/raspi/interrupt.h b/bolthur/kernel/platform/raspi/interrupt.h new file mode 100644 index 00000000..ebd8d3fe --- /dev/null +++ b/bolthur/kernel/platform/raspi/interrupt.h @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _PLATFORM_RASPI_INTERRUPT_H +#define _PLATFORM_RASPI_INTERRUPT_H + +// undocumented irq +#define IRQ_USB 9 +// documented irq +#define IRQ_MAILBOX 1 +#define IRQ_AUX 29 +#define IRQ_I2C_SPI 43 +#define IRQ_PWA0 45 +#define IRQ_PWA1 46 +#define IRQ_SMI 48 +#define IRQ_GPIO0 49 +#define IRQ_GPIO1 50 +#define IRQ_GPIO2 51 +#define IRQ_GPIO3 52 +#define IRQ_I2C 53 +#define IRQ_SPI 54 +#define IRQ_PCM 55 +#define IRQ_UART 57 + +#endif diff --git a/bolthur/kernel/platform/raspi/serial.c b/bolthur/kernel/platform/raspi/serial.c index f0fac2cb..f3b3819d 100644 --- a/bolthur/kernel/platform/raspi/serial.c +++ b/bolthur/kernel/platform/raspi/serial.c @@ -23,6 +23,7 @@ #include "peripheral.h" #include "gpio.h" #include "mailbox/property.h" +#include "interrupt.h" #include "../../io.h" #include "../../serial.h" @@ -211,11 +212,11 @@ bool serial_register_interrupt( void ) { // get peripheral base const uint32_t base = ( uint32_t )peripheral_base_get( PERIPHERAL_GPIO ); // register interrupt - if ( ! interrupt_register_handler( 57, serial_clear, NULL, INTERRUPT_FAST, true, false ) ) { + if ( ! interrupt_register_handler( IRQ_UART, serial_clear, NULL, INTERRUPT_FAST, true, false ) ) { return false; } // mask interrupt - io_out32( base + INTERRUPT_FIQ_CONTROL, 57 | 0x80 ); + io_out32( base + INTERRUPT_FIQ_CONTROL, IRQ_UART | 0x80 ); // flush it serial_flush(); return true; diff --git a/bolthur/kernel/syscall/interrupt.c b/bolthur/kernel/syscall/interrupt.c index eee51d33..feaeb2e2 100644 --- a/bolthur/kernel/syscall/interrupt.c +++ b/bolthur/kernel/syscall/interrupt.c @@ -17,6 +17,8 @@ * along with bolthur/kernel. If not, see . */ +#define PRINT_SYSCALL + #include #include "../task/process.h" #include "../task/thread.h" @@ -34,7 +36,7 @@ * @param context */ void syscall_interrupt_acquire( void* context ) { - uint8_t num = ( uint8_t )syscall_get_parameter( context, 0 ); + const uint8_t num = ( uint8_t )syscall_get_parameter( context, 0 ); // debug output #if defined( PRINT_SYSCALL ) DEBUG_OUTPUT( "syscall_interrupt_acquire( %"PRIu8" )\r\n", num ) @@ -81,7 +83,7 @@ void syscall_interrupt_acquire( void* context ) { * @param context */ void syscall_interrupt_release( void* context ) { - uint8_t num = ( uint8_t )syscall_get_parameter( context, 0 ); + const uint8_t num = ( uint8_t )syscall_get_parameter( context, 0 ); // debug output #if defined( PRINT_SYSCALL ) DEBUG_OUTPUT( "syscall_interrupt_release( %"PRIu8" )\r\n", num ) diff --git a/bolthur/server/platform/raspi/libhcd.h b/bolthur/server/platform/raspi/libhcd.h index 3127c811..f1153224 100644 --- a/bolthur/server/platform/raspi/libhcd.h +++ b/bolthur/server/platform/raspi/libhcd.h @@ -74,4 +74,12 @@ #define HCD_CHANNEL_INTERRUPT_FRAME_LIST_ROLLOVER ( 1 << 13 ) #define HCD_CHANNEL_INTERRUPT_RESERVED 0xffffc000 +// dwhci core ahb config values +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK ( 1 << 0 ) +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_SHIFT ( 1 << 0 ) // bcm2835 only +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_MASK ( 3 << 1 ) // bcm2835 only +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES ( 1 << 4 ) // bcm2835 only +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE ( 1 << 5 ) +#define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_AHB_SINGLE ( 1 << 23 ) + #endif diff --git a/bolthur/server/platform/raspi/storage/sd/emmc.c b/bolthur/server/platform/raspi/storage/sd/emmc.c index e5898361..5e7283e1 100644 --- a/bolthur/server/platform/raspi/storage/sd/emmc.c +++ b/bolthur/server/platform/raspi/storage/sd/emmc.c @@ -339,7 +339,7 @@ static emmc_response_t controller_startup( void ) { return EMMC_RESPONSE_MAILBOX; } // handle invalid device id returned - if ( 0 != request[ 5 ] ) { + if ( MAILBOX_POWER_STATE_DEVICE_SD_CARD != request[ 5 ] ) { // debug output #if defined( EMMC_ENABLE_DEBUG ) STARTUP_PRINT( "Invalid device id returned\r\n" ) diff --git a/bolthur/server/platform/raspi/usb/hcd/Makefile.am b/bolthur/server/platform/raspi/usb/hcd/Makefile.am index e8677f45..d6f82fa9 100644 --- a/bolthur/server/platform/raspi/usb/hcd/Makefile.am +++ b/bolthur/server/platform/raspi/usb/hcd/Makefile.am @@ -3,6 +3,8 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/hcd\" bin_PROGRAMS = hcd hcd_SOURCES = \ + rpc/interrupt/handle.c \ + rpc/init.c \ dwhci.c \ main.c \ response.c \ diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index 243af1a5..ad2fe9dc 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -18,16 +18,18 @@ */ // system includes +#include #include +#include // local includes #include "dwhci.h" #include "util.h" #include "response.h" // driver includes -#include - +#include "../../libhcd.h" #include "../../libiomem.h" #include "../../libperipheral.h" +#include "../../libmailbox.h" /** * @brief Static file descriptor for iomem operations @@ -82,7 +84,7 @@ response_t dwhci_query_vendor( uint32_t* destination ) { if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Mark interrupt as handled sequence failed\r\n" ) + STARTUP_PRINT( "Querying vendor information failed\r\n" ) #endif // return error return HCD_RESPONSE_ERROR_IO; @@ -95,6 +97,248 @@ response_t dwhci_query_vendor( uint32_t* destination ) { return HCD_RESPONSE_OK; } +/** + * @fn response_t dwhci_power_on(void) + * @brief Method to power on usb device + * @return power on result + */ +response_t dwhci_power_on( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Powering on usb device\r\n" ) + #endif + // allocate buffer + size_t request_size; + int32_t* request = util_prepare_mailbox( 8, &request_size ); + if ( ! request ) { + return HCD_RESPONSE_ERROR_MEMORY; + } + // build request + // buffer size + request[ 0 ] = ( int32_t )request_size; + // perform request + request[ 1 ] = 0; + // power state tag + request[ 2 ] = MAILBOX_SET_POWER_STATE; + // buffer and request size + request[ 3 ] = 8; + request[ 4 ] = 8; + // device id + request[ 5 ] = MAILBOX_POWER_STATE_DEVICE_USB_HCD; + // set power on and wait until it's stable + request[ 6 ] = MAILBOX_SET_POWER_STATE_ON | MAILBOX_SET_POWER_STATE_WAIT; + // end tag + request[ 7 ] = 0; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MAILBOX, + request_size, + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // free request + free( request ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // handle not successful + if ( MAILBOX_REQUEST_SUCCESSFUL != ( uint32_t )request[ 1 ] ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Request not successful: %#"PRIx32"\r\n", + ( uint32_t )request[ 1 ] ) + #endif + // free request + free( request ); + // return error + return HCD_RESPONSE_ERROR_MAILBOX; + } + // handle invalid device id returned + if ( MAILBOX_POWER_STATE_DEVICE_USB_HCD != request[ 5 ] ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( + "Invalid device id returned, expected %#x but received %#"PRIX32"\r\n", + MAILBOX_POWER_STATE_DEVICE_USB_HCD, request[ 5 ] ) + #endif + // free + free( request ); + // return error + return HCD_RESPONSE_ERROR_MAILBOX; + } + // check for powered on correctly + if ( ( request[ 6 ] & 0x3 ) != MAILBOX_SET_POWER_STATE_ON ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( + "Device not powered on successfully: %#"PRIx32"\r\n", + request[ 6 ] & 0x3 ) + #endif + // free + free( request ); + // return error + return HCD_RESPONSE_ERROR_MAILBOX; + } + // free + free( request ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_enable_global_interrupts( void ); + * @brief Wrapper to enable all interrupts + * @return + */ +response_t dwhci_enable_global_interrupts( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enabling all usb interrupts\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read ahb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + // mask all interrupts + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 1 ].value = HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable all interrupts failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @brief Method to disable global interrupts + * @return disable interrupt response + */ +response_t dwhci_disable_global_interrupts( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Disabling all usb interrupts\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read ahb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + // mask all interrupts + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Disable all interrupts failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_register_interrupt(void) + * @brief Method to register interrupt + * @return register response + */ +response_t dwhci_register_interrupt( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Try to acquire interrupt %d\r\n", ARM_IRQ_USB ) + #endif + // try to acquire usb interrupt + _syscall_interrupt_acquire( ARM_IRQ_USB ); + // handle error + if ( errno ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire interrupt %d: %s\r\n", ARM_IRQ_USB, + strerror( errno ) ) + #endif + // return io error + return HCD_RESPONSE_ERROR_IO; + } + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_init_core(void) + * @brief Init dwhci core + * @return + */ +response_t dwhci_init_core( void ) { + return HCD_RESPONSE_ERROR_NOT_IMPLEMENTED; +} + +/** + * @fn response_t dwhci_init_host(void) + * @brief Init dwhci host + * @return + */ +response_t dwhci_init_host( void ) { + return HCD_RESPONSE_ERROR_NOT_IMPLEMENTED; +} + /** * @fn response_t dwhci_init(void) * @brief Init dwhci @@ -110,6 +354,7 @@ response_t dwhci_init( void ) { // return error response return HCD_RESPONSE_ERROR_IO; } + // query vendor id uint32_t vendor; response_t result = dwhci_query_vendor( &vendor ); @@ -119,6 +364,8 @@ response_t dwhci_init( void ) { #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Query vendor information failed: %s\r\n", response_error( result ) ) #endif + // close fd_iomem again + close( fd_iomem ); // return result return result; } @@ -131,8 +378,7 @@ response_t dwhci_init( void ) { vendor >> 12 & 0xf, vendor >> 8 & 0xf, vendor >> 4 & 0xf, - vendor >> 0 & 0xf - ) + vendor >> 0 & 0xf ) #endif // check fetched vendor if ( ( vendor & 0xfffff000 ) != 0x4F542000 ) { @@ -140,10 +386,101 @@ response_t dwhci_init( void ) { #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "HCD: Driver incompatible\r\n" ) #endif + // close fd_iomem again + close( fd_iomem ); // return error return HCD_RESPONSE_ERROR_INCOMPATIBLE; } - /// FIXME: CONTINUE HCD INIT + + // power on usb device + result = dwhci_power_on(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on usb device: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + + // disable global interrupts + result = dwhci_disable_global_interrupts(); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to disable global interrupt: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + + // register interrupt handler + result = dwhci_register_interrupt(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to register interrupt: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + + // init core + result = dwhci_init_core(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to initialize core: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + + // enable global interrupts + result = dwhci_enable_global_interrupts(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to enable global interrupt: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + + // init core + result = dwhci_init_host(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to initialize host: %s\r\n", + response_error( result ) ) + #endif + // close fd_iomem again + close( fd_iomem ); + // return result + return result; + } + // return success return HCD_RESPONSE_OK; } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 9b2cee6e..1dba7516 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -26,6 +26,12 @@ #define DWHCI_ENABLE_DEBUG 1 response_t dwhci_query_vendor( uint32_t* destination ); +response_t dwhci_power_on( void ); +response_t dwhci_enable_global_interrupts( void ); +response_t dwhci_disable_global_interrupts( void ); +response_t dwhci_register_interrupt( void ); +response_t dwhci_init_core( void ); +response_t dwhci_init_host( void ); response_t dwhci_init( void ); #endif //_DWHCI_H diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index c2286d13..461c812d 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -17,12 +17,13 @@ * along with bolthur/kernel. If not, see . */ +// system includes #include #include - +// local includes #include "dwhci.h" #include "response.h" -#include "../../libperipheral.h" +#include "rpc.h" /** * @fn int main(int, char*[]) @@ -33,17 +34,23 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print starting - STARTUP_PRINT( "Setup hcd interface!\r\n" ) + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler" ); + return -1; + } - // init dwhci + // setup hcd interface + STARTUP_PRINT( "Setup hcd interface!\r\n" ) const response_t result = dwhci_init(); - // handle error if ( HCD_RESPONSE_OK != result ) { STARTUP_PRINT( "Unable to init dwhci: %s\r\n", response_error( result ) ); return -1; } + /// FIXME: IMPLEMENT + while ( true ) { __asm__ __volatile__ ( "nop" ); } diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc.h b/bolthur/server/platform/raspi/usb/hcd/rpc.h new file mode 100644 index 00000000..e7619153 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/rpc.h @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +bool rpc_init( void ); +void rpc_interrupt_handle( size_t, pid_t, size_t, size_t ); + +#endif diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/init.c b/bolthur/server/platform/raspi/usb/hcd/rpc/init.c new file mode 100644 index 00000000..6477c1ac --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/init.c @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +// local includes +#include "../rpc.h" +// driver includes +#include "../../../libhcd.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + // bind interrupt handler + bolthur_rpc_bind( ARM_IRQ_USB, rpc_interrupt_handle, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register handler read!\r\n" ) + return false; + } + // return success + return true; +} diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/interrupt/handle.c b/bolthur/server/platform/raspi/usb/hcd/rpc/interrupt/handle.c new file mode 100644 index 00000000..2f7fa526 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/interrupt/handle.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "../../rpc.h" + +/** + * @fn void rpc_interrupt_handle(size_t, pid_t, size_t, size_t) + * @brief Interrupt handler + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_interrupt_handle( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { + STARTUP_PRINT( "Interrupt handler called\r\n" ) +} From 43ef57b7b64ba9521054db0724104b93f6a609f6 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 21 Jul 2025 21:49:37 +0200 Subject: [PATCH 004/144] - First iteration of raspi hcd server currently setting up dwhci done - Added new generic libhcd and libusb to server folder - Adjusted include guards of raspi platform lib files - Added new empty submit control message rpc to hcd server later used by usbd - Added enable rpc, send of device file and wait for rpc to hcd server --- bolthur/server/libhcd.h | 32 + bolthur/server/libusb.h | 25 + bolthur/server/platform/raspi/libdma.h | 4 +- bolthur/server/platform/raspi/libemmc.h | 4 +- bolthur/server/platform/raspi/libgpio.h | 4 +- bolthur/server/platform/raspi/libhcd.h | 68 +- bolthur/server/platform/raspi/libiomem.h | 4 +- bolthur/server/platform/raspi/libmailbox.h | 4 +- bolthur/server/platform/raspi/libperipheral.h | 4 +- bolthur/server/platform/raspi/libsdhost.h | 4 +- .../server/platform/raspi/usb/hcd/Makefile.am | 1 + bolthur/server/platform/raspi/usb/hcd/dwhci.c | 1446 ++++++++++++++++- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 10 + bolthur/server/platform/raspi/usb/hcd/main.c | 22 +- bolthur/server/platform/raspi/usb/hcd/rpc.h | 1 + .../server/platform/raspi/usb/hcd/rpc/init.c | 7 + .../usb/hcd/rpc/submit_control_message.c | 37 + 17 files changed, 1655 insertions(+), 22 deletions(-) create mode 100644 bolthur/server/libhcd.h create mode 100644 bolthur/server/libusb.h create mode 100644 bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c diff --git a/bolthur/server/libhcd.h b/bolthur/server/libhcd.h new file mode 100644 index 00000000..12c0fb4e --- /dev/null +++ b/bolthur/server/libhcd.h @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIBHCD_H +#define _LIBHCD_H + +#include +#include +#include +#include +#include +#include "libusb.h" + +#define HCD_SUBMIT_CONTROL_MESSAGE RPC_CUSTOM_START + +#endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h new file mode 100644 index 00000000..6f43bc83 --- /dev/null +++ b/bolthur/server/libusb.h @@ -0,0 +1,25 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIBUSB_H +#define _LIBUSB_H + + + +#endif diff --git a/bolthur/server/platform/raspi/libdma.h b/bolthur/server/platform/raspi/libdma.h index a287f10a..320a49f1 100644 --- a/bolthur/server/platform/raspi/libdma.h +++ b/bolthur/server/platform/raspi/libdma.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBDMA_H -#define _LIBDMA_H +#ifndef _PLATFORM_RASPI_LIBDMA_H +#define _PLATFORM_RASPI_LIBDMA_H // control and status #define LIBDMA_CS_ACTIVE ( 1U << 0 ) diff --git a/bolthur/server/platform/raspi/libemmc.h b/bolthur/server/platform/raspi/libemmc.h index b4b72833..f6476431 100644 --- a/bolthur/server/platform/raspi/libemmc.h +++ b/bolthur/server/platform/raspi/libemmc.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBEMMC_H -#define _LIBEMMC_H +#ifndef _PLATFORM_RASPI_LIBEMMC_H +#define _PLATFORM_RASPI_LIBEMMC_H // command register #define EMMC_CMDTM_CMD_TYPE_NORMAL ( 0 << 22 ) diff --git a/bolthur/server/platform/raspi/libgpio.h b/bolthur/server/platform/raspi/libgpio.h index 2f048724..f4c9db6c 100644 --- a/bolthur/server/platform/raspi/libgpio.h +++ b/bolthur/server/platform/raspi/libgpio.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBGPIO_H -#define _LIBGPIO_H +#ifndef _PLATFORM_RASPI_LIBGPIO_H +#define _PLATFORM_RASPI_LIBGPIO_H enum iomem_gpio_enum_function { IOMEM_GPIO_ENUM_FUNCTION_INPUT = 0x0, diff --git a/bolthur/server/platform/raspi/libhcd.h b/bolthur/server/platform/raspi/libhcd.h index f1153224..43615978 100644 --- a/bolthur/server/platform/raspi/libhcd.h +++ b/bolthur/server/platform/raspi/libhcd.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBHCD_H -#define _LIBHCD_H +#ifndef _PLATFORM_RASPI_LIBHCD_H +#define _PLATFORM_RASPI_LIBHCD_H // interrupt #define ARM_IRQ_USB 9 @@ -74,6 +74,11 @@ #define HCD_CHANNEL_INTERRUPT_FRAME_LIST_ROLLOVER ( 1 << 13 ) #define HCD_CHANNEL_INTERRUPT_RESERVED 0xffffc000 +// fifo stuff +#define HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE 1024 // number of 32 bit words +#define HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE 1024 // number of 32 bit words +#define HCD_DWHCI_CFG_HOST_PER_TX_FIFO_SIZE 1024 // number of 32 bit words + // dwhci core ahb config values #define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK ( 1 << 0 ) #define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_SHIFT ( 1 << 0 ) // bcm2835 only @@ -81,5 +86,64 @@ #define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES ( 1 << 4 ) // bcm2835 only #define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE ( 1 << 5 ) #define HCD_DWHCI_CORE_AHB_CFG_GLOBAL_AHB_SINGLE ( 1 << 23 ) +// dwhci core usb config values + #define HCD_DWHCI_CORE_USB_CFG_PHYIF ( 1 << 3 ) + #define HCD_DWHCI_CORE_USB_CFG_ULPI_UTMI_SEL ( 1 << 4 ) + #define HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE ( 1 << 8 ) + #define HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE ( 1 << 9 ) + #define HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS ( 1 << 17 ) + #define HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M ( 1 << 19 ) + #define HCD_DWHCI_CORE_USB_CFG_ULPI_EXT_VBUS_DRV ( 1 << 20 ) + #define HCD_DWHCI_CORE_USB_CFG_TERM_SEL_DL_PULSE ( 1 << 22 ) +// dwhci reset usb values + #define HCD_DWHCI_CORE_RESET_SOFT_RESET ( 1 << 0 ) + #define HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH ( 1 << 4 ) + #define HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH ( 1 << 5 ) + #define HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT 6 + #define HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_MASK ( 0x1F << 6 ) + #define HCD_DWHCI_CORE_RESET_AHB_IDLE ( 1 << 31 ) +// dwhci cfg2 values +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE( reg ) ( ( ( reg ) >> 0 ) & 7 ) +#define HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE( reg ) ( ( ( reg ) >> 3 ) & 3 ) +#define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( reg ) ( ( ( reg ) >> 6 ) & 3 ) +#define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 +#define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_UTMI 1 +#define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI 2 +#define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_UTMI_ULPI 3 +#define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( reg ) ( ( ( reg ) >> 8 ) & 3 ) +#define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED 1 +#define HCD_DWHCI_CORE_HW_CFG2_NUM_HOST_CHANNELS( reg ) ( ( ( ( reg ) >> 14 ) & 0xF ) + 1 ) +// dwhci host cfg values +#define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_SHIFT 0 +#define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_MASK ( 3 << 0 ) +#define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_30_60_MHZ 0 +#define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ 1 +#define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_6_MHZ 2 +// dwhci host port values +#define HCD_DWHCI_HOST_PORT_CONNECT ( 1 << 0 ) +#define HCD_DWHCI_HOST_PORT_CONNECT_CHANGED ( 1 << 1 ) +#define HCD_DWHCI_HOST_PORT_ENABLE ( 1 << 2 ) +#define HCD_DWHCI_HOST_PORT_ENABLE_CHANGED ( 1 << 3 ) +#define HCD_DWHCI_HOST_PORT_OVERCURRENT ( 1 << 4 ) +#define HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED ( 1 << 5 ) +#define HCD_DWHCI_HOST_PORT_RESET ( 1 << 8 ) +#define HCD_DWHCI_HOST_PORT_POWER ( 1 << 12 ) +#define HCD_DWHCI_HOST_PORT_SPEED( reg ) ( ( ( reg ) >> 17 ) & 3 ) +#define HCD_DWHCI_HOST_PORT_SPEED_HIGH 0 +#define HCD_DWHCI_HOST_PORT_SPEED_FULL 1 +#define HCD_DWHCI_HOST_PORT_SPEED_LOW 2 +#define HCD_DWHCI_HOST_PORT_DEFAULT_MASK ( HCD_DWHCI_HOST_PORT_CONNECT_CHANGED \ + | HCD_DWHCI_HOST_PORT_ENABLE | HCD_DWHCI_HOST_PORT_ENABLE_CHANGED | HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED ) +// core interrupt values +#define HCD_DWHCI_CORE_INT_MASK_MODE_MISMATCH ( 1 << 1 ) +#define HCD_DWHCI_CORE_INT_MASK_SOF_INTR ( 1 << 3 ) +#define HCD_DWHCI_CORE_INT_MASK_RX_STS_Q_LVL ( 1 << 4 ) +#define HCD_DWHCI_CORE_INT_MASK_USB_SUSPEND ( 1 << 11 ) +#define HCD_DWHCI_CORE_INT_MASK_PORT_INTR ( 1 << 24 ) +#define HCD_DWHCI_CORE_INT_MASK_HC_INTR ( 1 << 25 ) +#define HCD_DWHCI_CORE_INT_MASK_CON_ID_STS_CHNG ( 1 << 28 ) +#define HCD_DWHCI_CORE_INT_MASK_DISCONNECT ( 1 << 29 ) +#define HCD_DWHCI_CORE_INT_MASK_SESS_REQ_INTR ( 1 << 30 ) +#define HCD_DWHCI_CORE_INT_MASK_WKUP_INTR ( 1 << 31 ) #endif diff --git a/bolthur/server/platform/raspi/libiomem.h b/bolthur/server/platform/raspi/libiomem.h index 84e75a03..9530cf40 100644 --- a/bolthur/server/platform/raspi/libiomem.h +++ b/bolthur/server/platform/raspi/libiomem.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBIOMEM_H -#define _LIBIOMEM_H +#ifndef _PLATFORM_RASPI_LIBIOMEM_H +#define _PLATFORM_RASPI_LIBIOMEM_H #include #include diff --git a/bolthur/server/platform/raspi/libmailbox.h b/bolthur/server/platform/raspi/libmailbox.h index 8f073299..8e9b7f72 100644 --- a/bolthur/server/platform/raspi/libmailbox.h +++ b/bolthur/server/platform/raspi/libmailbox.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBMAILBOX_H -#define _LIBMAILBOX_H +#ifndef _PLATFORM_RASPI_LIBMAILBOX_H +#define _PLATFORM_RASPI_LIBMAILBOX_H #define MAILBOX_REQUEST_SUCCESSFUL 0x80000000 diff --git a/bolthur/server/platform/raspi/libperipheral.h b/bolthur/server/platform/raspi/libperipheral.h index da1a952b..fb370d84 100644 --- a/bolthur/server/platform/raspi/libperipheral.h +++ b/bolthur/server/platform/raspi/libperipheral.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBPERIPHERAL_H -#define _LIBPERIPHERAL_H +#ifndef _PLATFORM_RASPI_LIBPERIPHERAL_H +#define _PLATFORM_RASPI_LIBPERIPHERAL_H // mailbox offset #define PERIPHERAL_MAILBOX_OFFSET 0xB880 diff --git a/bolthur/server/platform/raspi/libsdhost.h b/bolthur/server/platform/raspi/libsdhost.h index 971937ee..41f08212 100644 --- a/bolthur/server/platform/raspi/libsdhost.h +++ b/bolthur/server/platform/raspi/libsdhost.h @@ -17,8 +17,8 @@ * along with bolthur/kernel. If not, see . */ -#ifndef _LIBSDHOST_H -#define _LIBSDHOST_H +#ifndef _PLATFORM_RASPI_LIBSDHOST_H +#define _PLATFORM_RASPI_LIBSDHOST_H // command register #define SDHOST_COMMAND_FLAG_ENABLE ( 1 << 15 ) diff --git a/bolthur/server/platform/raspi/usb/hcd/Makefile.am b/bolthur/server/platform/raspi/usb/hcd/Makefile.am index d6f82fa9..c32eacac 100644 --- a/bolthur/server/platform/raspi/usb/hcd/Makefile.am +++ b/bolthur/server/platform/raspi/usb/hcd/Makefile.am @@ -5,6 +5,7 @@ bin_PROGRAMS = hcd hcd_SOURCES = \ rpc/interrupt/handle.c \ rpc/init.c \ + rpc/submit_control_message.c \ dwhci.c \ main.c \ response.c \ diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index ad2fe9dc..d6c6c47a 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -86,6 +86,8 @@ response_t dwhci_query_vendor( uint32_t* destination ) { #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Querying vendor information failed\r\n" ) #endif + // free sequence + free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } @@ -234,6 +236,8 @@ response_t dwhci_enable_global_interrupts( void ) { #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Enable all interrupts failed\r\n" ) #endif + // free sequence + free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } @@ -286,6 +290,8 @@ response_t dwhci_disable_global_interrupts( void ) { #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Disable all interrupts failed\r\n" ) #endif + // free sequence + free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } @@ -321,13 +327,1020 @@ response_t dwhci_register_interrupt( void ) { return HCD_RESPONSE_OK; } +/** + * @fn response_t dwhci_reset_device(void) + * @brief Reset dwhci device + * @return + */ +response_t dwhci_reset_device( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Reset device\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 5, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // loop while ahb idle + sequence[ 0 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 0 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_AHB_IDLE; + sequence[ 0 ].loop_max_iteration = 10; + sequence[ 0 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 0 ].sleep = 10; + // read reset value + sequence[ 1 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + // core soft reset + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 2 ].value = HCD_DWHCI_CORE_RESET_SOFT_RESET; + // wait until it's gone + sequence[ 3 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 3 ].loop_and = HCD_DWHCI_CORE_RESET_SOFT_RESET; + sequence[ 3 ].loop_max_iteration = 10; + sequence[ 3 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 3 ].sleep = 10; + // delay 100 ms + sequence[ 4 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 4 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 4 ].sleep = 100; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Reset sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // check for first timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 0 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for idle timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // check for second timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 3 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for reset timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // free sequence again + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_enable_common_interrupts(void) + * @brief Enable common interrupts + * @return + */ +response_t dwhci_enable_common_interrupts( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable common interrupts\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read interrupt stat + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_STAT; + // enable all interrupts + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_INT_STAT; + sequence[ 1 ].value = ( uint32_t )-1; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence failed\r\n" ) /// FIXME: PROVIDE SOME MEANINGFUL OUTPUT + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_read_core_cfg2(uint32_t*) + * @brief Wrapper to read cfg2 + * @param cfg2 + * @return + */ +response_t dwhci_read_core_cfg2( uint32_t* cfg2 ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read cfg2\r\n" ) + #endif + // validate parameter + if ( ! cfg2 ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "No pointer passed for result\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_EINVAL; + } + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG2; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // write back result + *cfg2 = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_read_core_cfg(uint32_t*) + * @brief Wrapper to read cfg + * @param cfg + * @return + */ +response_t dwhci_read_core_cfg( uint32_t* cfg ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read usb cfg\r\n" ) + #endif + // validate parameter + if ( ! cfg ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "No pointer passed for result\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_EINVAL; + } + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // write back result + *cfg = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + /** * @fn response_t dwhci_init_core(void) * @brief Init dwhci core * @return */ response_t dwhci_init_core( void ) { - return HCD_RESPONSE_ERROR_NOT_IMPLEMENTED; + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Init core\r\n" ) + #endif + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read core usb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_ULPI_EXT_VBUS_DRV; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_TERM_SEL_DL_PULSE; + // perform request + int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence failed\r\n" ) /// FIXME: PROVIDE SOME MEANINGFUL OUTPUT + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + + // reset dwhci device + response_t result = dwhci_reset_device(); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Reset device failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // allocate sequence + sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read core usb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_ULPI_UTMI_SEL; + // write prevoius read with logical and + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + // select utmi+ and utmi width of 8 + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_PHYIF; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "select utmi+ and utmi width of 8 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + + uint32_t cfg2; + result = dwhci_read_core_cfg2( &cfg2 ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of core cfg2 failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // handle wrong architecture + if ( HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE( cfg2 ) != 2 ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unsupported architecture\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_INCOMPATIBLE; + } + + uint32_t cfg; + result = dwhci_read_core_cfg( &cfg ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // set configuration depending on cfg2 + if ( + HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI + && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED + ) { + cfg |= + HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS + | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M; + } else { + cfg &= ( uint32_t )( + ~HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS + & ~HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M + ); + } + + // write back cfg + // allocate sequence + sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // write back cfg2 + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 0 ].value = cfg; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "write back of core usb cfg failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + + // read cfg2 again + result = dwhci_read_core_cfg2( &cfg2 ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of core cfg2 failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // validate number of channels + const uint32_t num_channel = HCD_DWHCI_CORE_HW_CFG2_NUM_HOST_CHANNELS( cfg2 ); + if ( ! ( 4 <= num_channel && num_channel <= PERIPHERAL_DWHCI_MAX_CHANNELS ) ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Invalid number of channels\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_INCOMPATIBLE; + } + + // read ahb cfg + // allocate sequence + sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "read of usb core failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // cache it in a variable + uint32_t ahb_cfg = sequence[ 0 ].value; + // free sequence + free( sequence ); + // manipulate config + ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; + ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES; + ahb_cfg &= ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_MASK; + // allocate sequence to write it back + sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 0 ].value = ahb_cfg; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "write back of ahb config\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + + // hnp and srp are not used + // allocate sequence + sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE; + // write previous read with and + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "read of usb core failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence again + free( sequence ); + + // enable common interrupts + result = dwhci_enable_common_interrupts(); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "enable common interrupts failed: %s\r\n", + response_error( result ) ) + #endif + // return error + return result; + } + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_read_host_cfg(uint32_t*) + * @brief Wrapper to read cfg + * @param cfg + * @return + */ +response_t dwhci_read_host_cfg( uint32_t* cfg ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read usb host cfg\r\n" ) + #endif + // validate parameter + if ( ! cfg ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "No pointer passed for result\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_EINVAL; + } + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // write back result + *cfg = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_core_flush_tx_fifo(const uint32_t) + * @brief Wrapper to flush tx fifo + * @param num_fifo num fifo + * @return + * + * @todo check whether loop is correct + */ +response_t dwhci_core_flush_tx_fifo( const uint32_t num_fifo ) { + // debug output + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo %#"PRIx32"\r\n", num_fifo ) + #endif + + // set initial reset fifo flush + const uint32_t reset = ( + HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH + & ( uint32_t )~HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_MASK + ) | ( num_fifo << HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT ); + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // write reset config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 0 ].value = reset; + // loop while it's there + sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH; + sequence[ 1 ].loop_max_iteration = 10; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 1; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // check for timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // free sequence again + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_core_flush_rx_fifo(void) + * @brief Wrapper to flush rx fifo + * @return + */ +response_t dwhci_core_flush_rx_fifo( void ) { + // debug output + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing rx fifo\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // write reset config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 0 ].value = HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; + // loop while it's there + sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; + sequence[ 1 ].loop_max_iteration = 10; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 10; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // check for timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // free sequence again + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_read_host_cfg(uint32_t*) + * @brief Wrapper to read cfg + * @param port + * @return + */ +response_t dwhci_read_host_port( uint32_t* port ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read usb host cfg\r\n" ) + #endif + // validate parameter + if ( ! port ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "No pointer passed for result\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_EINVAL; + } + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // write back result + *port = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_enable_host_interrupts(void); + * @brief Wrapper to enable host interrupts + * @return + */ +response_t dwhci_enable_host_interrupts( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable host interrupts\r\n" ) + #endif + + // reset core interrupts + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; + sequence[ 0 ].value = 0; + // perform request + int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + + // enable common interrupts again + const response_t result = dwhci_enable_common_interrupts(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable host interrupts failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // read core interrupts again and enable host interrupts + // allocate sequence + sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; + // write with or previous read + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; + sequence[ 1 ].value = HCD_DWHCI_CORE_INT_MASK_HC_INTR; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable of host interrupts failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + + // return success + return HCD_RESPONSE_OK; } /** @@ -336,7 +1349,422 @@ response_t dwhci_init_core( void ) { * @return */ response_t dwhci_init_host( void ) { - return HCD_RESPONSE_ERROR_NOT_IMPLEMENTED; + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Initialize host\r\n" ) + #endif + // set phy power + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 0 ].value = 0; + // perform request + int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence again + free( sequence ); + + // read out host config + uint32_t host_cfg; + response_t result = dwhci_read_host_cfg( &host_cfg ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of host cfg failed: %s\r\n", response_error( result ) ) + #endif + // return error + return result; + } + host_cfg &= ( uint32_t )~HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_MASK; + + // read core cfg + uint32_t core_cfg2; + result = dwhci_read_core_cfg2( &core_cfg2 ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // read core cfg + uint32_t core_cfg; + result = dwhci_read_core_cfg( &core_cfg ); + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // adjust host config + if ( + HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI + && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED + && HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS == core_cfg + ) { + host_cfg |= HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ; + } else { + host_cfg |= HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_30_60_MHZ; + } + + // write back host config + // allocate sequence + sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + sequence[ 0 ].value = host_cfg; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence again + free( sequence ); + + // write rx fifo size, non-periodic tx fifo size and host periodic fifo size + // allocate sequence + sequence = util_prepare_mmio_sequence( 3, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // write rx fifo size + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RX_FIFO_SIZ; + sequence[ 0 ].value = HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE; + // write non-periodic tx fifo size + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_NPER_FIFO_SIZ; + sequence[ 1 ].value = HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE | + ( HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE << 16 ); + // write host periodic fifo size + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_HOST_PER_TX_FIFO_SZ; + sequence[ 2 ].value = ( HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE + HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE ) + | HCD_DWHCI_CFG_HOST_PER_TX_FIFO_SIZE << 16; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence again + free( sequence ); + + // flush rx fifo + result = dwhci_core_flush_tx_fifo( 0x10 ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flush tx fifo failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // flush tx fifo + result = dwhci_core_flush_rx_fifo(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flush rx fifo failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // read port + uint32_t port; + result = dwhci_read_host_port( &port ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read host port failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + // mask port result + port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; + // set power if not set + if ( ! ( port & HCD_DWHCI_HOST_PORT_POWER ) ) { + // set flag + port |= HCD_DWHCI_HOST_PORT_POWER; + // write port back + // allocate sequence + sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 0 ].value = port; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Write back of host port failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence again + free( sequence ); + } + + // enable host interrupts + result = dwhci_enable_host_interrupts(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable host interrupt failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_enable_root_port(void) + * @brief Wrapper to enable root port + * @return + */ +response_t dwhci_enable_root_port( void ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable root port\r\n" ) + #endif + + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 0 ].loop_and = ( uint32_t )HCD_DWHCI_HOST_PORT_CONNECT; + sequence[ 0 ].loop_max_iteration = 10; + sequence[ 0 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 0 ].sleep = 10; + // wait a bit + sequence[ 1 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 100; + // perform request + int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for host port command sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // check for valid timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 0 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for host port connect timed out, not really an error\r\n" ) + #endif + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; + } + // free sequence again + free( sequence ); + + // read host port + uint32_t host_port; + response_t result = dwhci_read_host_port( &host_port ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read host port failed: %s\r\n", response_error( result ) ) + #endif + // return result + return result; + } + // mask host port and set reset + host_port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; + host_port |= HCD_DWHCI_HOST_PORT_RESET; + // write back value with delay and another write of host port + // allocate sequence + sequence = util_prepare_mmio_sequence( 5, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 0 ].value = host_port; + // wait a bit + sequence[ 1 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 50; + // read host port + sequence[ 2 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 2 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; + // write back with and + sequence[ 3 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 3 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_RESET; + // wait a bit + sequence[ 4 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 4 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 4 ].sleep = 20; + // perform request + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Write back of host port failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; } /** @@ -481,6 +1909,20 @@ response_t dwhci_init( void ) { return result; } + // enable root port + result = dwhci_enable_root_port(); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Enable root port failed: %s\r\n", response_error( result ) ) + #endif + // close fd iomem + close( fd_iomem ); + // return result + return result; + } + // return success return HCD_RESPONSE_OK; } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 1dba7516..5b5617f9 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -30,8 +30,18 @@ response_t dwhci_power_on( void ); response_t dwhci_enable_global_interrupts( void ); response_t dwhci_disable_global_interrupts( void ); response_t dwhci_register_interrupt( void ); +response_t dwhci_reset_device( void ); +response_t dwhci_enable_common_interrupts( void ); +response_t dwhci_read_core_cfg2( uint32_t* ); +response_t dwhci_read_core_cfg( uint32_t* ); response_t dwhci_init_core( void ); +response_t dwhci_read_host_cfg( uint32_t* ); +response_t dwhci_core_flush_tx_fifo( uint32_t ); +response_t dwhci_core_flush_rx_fifo( void ); +response_t dwhci_read_host_port( uint32_t* ); +response_t dwhci_enable_host_interrupts( void ); response_t dwhci_init_host( void ); +response_t dwhci_enable_root_port( void ); response_t dwhci_init( void ); #endif //_DWHCI_H diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index 461c812d..6a085097 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -24,6 +24,9 @@ #include "dwhci.h" #include "response.h" #include "rpc.h" +// driver includes +#include "../../../../libhcd.h" +#include "../../../../libhelper.h" /** * @fn int main(int, char*[]) @@ -49,10 +52,21 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } - /// FIXME: IMPLEMENT + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); - while ( true ) { - __asm__ __volatile__ ( "nop" ); + // add device file + STARTUP_PRINT( "Sending device to vfs\r\n" ) + uint32_t device_info[] = { HCD_SUBMIT_CONTROL_MESSAGE, }; + STARTUP_PRINT( "HCD_SUBMIT_CONTROL_MESSAGE = %d\r\n", HCD_SUBMIT_CONTROL_MESSAGE ) + if ( !dev_add_file( "/dev/usb/hcd", device_info, 1 ) ) { + STARTUP_PRINT( "Unable to add dev hcd\r\n" ) + return -1; } - return -1; + + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc.h b/bolthur/server/platform/raspi/usb/hcd/rpc.h index e7619153..68a8e0bc 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc.h +++ b/bolthur/server/platform/raspi/usb/hcd/rpc.h @@ -25,5 +25,6 @@ bool rpc_init( void ); void rpc_interrupt_handle( size_t, pid_t, size_t, size_t ); +void rpc_submit_control_message( size_t, pid_t, size_t, size_t ); #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/init.c b/bolthur/server/platform/raspi/usb/hcd/rpc/init.c index 6477c1ac..16eab70e 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/init.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/init.c @@ -23,6 +23,7 @@ #include "../rpc.h" // driver includes #include "../../../libhcd.h" +#include "../../../../../libhcd.h" /** * @fn bool rpc_init(void) @@ -36,6 +37,12 @@ bool rpc_init( void ) { STARTUP_PRINT( "Unable to register handler read!\r\n" ) return false; } + // bind rpc handler for communication + bolthur_rpc_bind( HCD_SUBMIT_CONTROL_MESSAGE, rpc_submit_control_message, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register handler submit control message!\r\n" ) + return false; + } // return success return true; } diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c new file mode 100644 index 00000000..ad0f4039 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "../rpc.h" + +/** + * @fn void rpc_submit_control_message(size_t, pid_t, size_t, size_t) + * @brief Interrupt handler + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_submit_control_message( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { + STARTUP_PRINT( "Interrupt handler called\r\n" ) +} From 2900a461c0d7446596cdcea71f3a1a0ea7cbbb44 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 21 Jul 2025 23:27:54 +0200 Subject: [PATCH 005/144] - Generated libusb header with a subset of usb structures - Added hct_submit_control_message_t type for hcd rpc - Filled submit_control_message rpc with a bit of logic to at least read message from mailbox --- bolthur/server/libhcd.h | 10 +- bolthur/server/libusb.h | 248 ++++++++++++++++++ .../usb/hcd/rpc/submit_control_message.c | 48 +++- 3 files changed, 298 insertions(+), 8 deletions(-) diff --git a/bolthur/server/libhcd.h b/bolthur/server/libhcd.h index 12c0fb4e..5e398580 100644 --- a/bolthur/server/libhcd.h +++ b/bolthur/server/libhcd.h @@ -20,13 +20,15 @@ #ifndef _LIBHCD_H #define _LIBHCD_H -#include -#include -#include -#include #include #include "libusb.h" #define HCD_SUBMIT_CONTROL_MESSAGE RPC_CUSTOM_START +typedef struct { + libusb_pipe_address_t pipe_address; + libusb_device_request_t request; + uint8_t buffer[]; +} hcd_submit_control_message_t; + #endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 6f43bc83..f1ec8280 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -20,6 +20,254 @@ #ifndef _LIBUSB_H #define _LIBUSB_H +// disable a bunch of warnings necessary to build packed structures +// for usb communication +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpacked" +#pragma GCC diagnostic ignored "-Wattributes" +#include + +typedef enum { + LIBUSB_DESCRIPTOR_DEVICE = 1, + LIBUSB_DESCRIPTOR_CONFIGURATION = 2, + LIBUSB_DESCRIPTOR_STRING = 3, + LIBUSB_DESCRIPTOR_INTERFACE = 4, + LIBUSB_DESCRIPTOR_ENDPOINT = 5, + LIBUSB_DESCRIPTOR_DEVICE_QUALIFIER = 6, + LIBUSB_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, + LIBUSB_DESCRIPTOR_INTERFACE_POWER = 8, + LIBUSB_DESCRIPTOR_HID = 33, + LIBUSB_DESCRIPTOR_HID_REPORT = 34, + LIBUSB_DESCRIPTOR_HID_PHYSICAL = 35, + LIBUSB_DESCRIPTOR_HUB = 41, +} libusb_descriptor_type_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; +} libusb_descriptor_header_t; + +typedef enum { + LIBUSB_DEVICE_CLASS_IN_INTERFACE = 0x00, + LIBUSB_DEVICE_CLASS_COMMUNICATIONS = 0x02, + LIBUSB_DEVICE_CLASS_HUB = 0x09, + LIBUSB_DEVICE_CLASS_DIAGNOSTIC = 0xdc, + LIBUSB_DEVICE_CLASS_MISCELLANEOUS = 0xef, + LIBUSB_DEVICE_CLASS_VENDOR_SPECIFIC = 0xff, +} libusb_device_class_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t usb_version; + libusb_device_class_t class : 8; + uint8_t subclass; + uint8_t protocol; + uint8_t max_packet_size0; + uint16_t vendor_id; + uint16_t product_id; + uint16_t version; + uint8_t manufacturer; + uint8_t product; + uint8_t serial_number; + uint8_t configuration_count; +} libusb_device_descriptor_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t usb_version; + libusb_device_class_t class : 8; + uint8_t subclass; + uint8_t protocol; + uint8_t max_packet_size0; + uint8_t configuration_count; + uint8_t _reserved; +} libusb_device_qualifier_descriptor_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t total_length; + uint8_t interface_count; + uint8_t configuration_value; + uint8_t string_index; + struct __packed { + uint8_t reserved0 : 5; + bool remote_wakeup : 1; + bool self_powered : 1; + uint8_t reserved1 : 1; + } attributes; + uint8_t maximum_power; +} libusb_configuration_descriptor_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t total_length; + uint8_t interface_count; + uint8_t configuration_value; + uint8_t interface_number; + struct __packed { + uint8_t reserved0 : 5; + bool remote_wakeup : 1; + bool self_powered : 1; + uint8_t reserved1 : 1; + } attributes; + uint8_t maximum_power; +} libusb_other_speed_configuration_descriptor_t; + +typedef enum { + LIBUSB_INTERFACE_CLASS_RESERVED = 0x00, + LIBUSB_INTERFACE_CLASS_AUDIO = 0x01, + LIBUSB_INTERFACE_CLASS_COMMUNICATIONS = 0x02, + LIBUSB_INTERFACE_CLASS_HID = 0x03, + LIBUSB_INTERFACE_CLASS_PHYSICAL = 0x05, + LIBUSB_INTERFACE_CLASS_IMAGE = 0x06, + LIBUSB_INTERFACE_CLASS_PRINTER = 0x07, + LIBUSB_INTERFACE_CLASS_MASS_STORAGE = 0x08, + LIBUSB_INTERFACE_CLASS_HUB = 0x09, + LIBUSB_INTERFACE_CLASS_CDC_DATA = 0x0a, + LIBUSB_INTERFACE_CLASS_SMART_CARD = 0x0b, + LIBUSB_INTERFACE_CLASS_CONTENT_SECURITY = 0x0d, + LIBUSB_INTERFACE_CLASS_VIDEO = 0x0e, + LIBUSB_INTERFACE_CLASS_PERSONAL_HEALTHCARE = 0x0f, + LIBUSB_INTERFACE_CLASS_AUDIO_VIDEO = 0x10, + LIBUSB_INTERFACE_CLASS_DIAGNOSTIC_DEVICE = 0xdc, + LIBUSB_INTERFACE_CLASS_WIRELESS_CONTROLLER = 0xe0, + LIBUSB_INTERFACE_CLASS_MISCELLANEOUS = 0xef, + LIBUSB_INTERFACE_CLASS_APPLICATION_SPECIFIC = 0xfe, + LIBUSB_INTERFACE_CLASS_VENDOR_SPECIFIC = 0xff, +} libusb_interface_class_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint8_t number; + uint8_t alternate_setting; + uint8_t endpoint_count; + libusb_interface_class_t class : 8; + uint8_t subclass; + uint8_t protocol; + uint8_t string_index; +} libusb_interface_descriptor_t; + +typedef enum { + LIBUSB_DIRECTION_HOST_TO_DEVICE = 0, + LIBUSB_DIRECTION_OUT = 0, + LIBUSB_DIRECTION_DEVICE_TO_HOST = 1, + LIBUSB_DIRECTION_IN = 1, +} libusb_direction_t; + +typedef enum { + LIBUSB_TRANSFER_CONTROL = 0, + LIBUSB_TRANSFER_ISOCHRONOUS = 1, + LIBUSB_TRANSFER_BULK = 2, + LIBUSB_TRANSFER_INTERRUPT = 3, +} libusb_transfer_t; + +typedef enum { + LIBUSB_SYNCHRONIZATION_NO_SYNCHRONIZATION = 0, + LIBUSB_SYNCHRONIZATION_ASYNCHRONOUS = 1, + LIBUSB_SYNCHRONIZATION_ADAPTIVE = 2, + LIBUSB_SYNCHRONIZATION_SYNCHRONOUS = 3, +} libusb_synchronization_t; + +typedef enum { + LIBUSB_USAGE_DATA = 0, + LIBUSB_USAGE_FEEDBACK = 1, + LIBUSB_USAGE_IMPLICIT_FEEDBACK_DATA = 2, +} libusb_usage_t; + +typedef enum { + LIBUSB_TRANSACTIONS_NONE = 0, + LIBUSB_TRANSACTIONS_EXTRA1 = 1, + LIBUSB_TRANSACTIONS_EXTRA2 = 2, +} libusb_transactions_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + struct __packed { + uint8_t number : 4; + uint8_t reserved : 3; + libusb_direction_t direction : 1; + } endpoint_address; + struct __packed { + libusb_transfer_t transfer : 2; + libusb_synchronization_t synchronization : 2; + libusb_usage_t usage : 2; + uint8_t reserved : 2; + } attributes; + struct __packed { + uint16_t max_size : 11; + libusb_transactions_t transactions : 2; + uint8_t reserved : 3; + } packet; + uint8_t interval; +} libusb_endpoint_descriptor_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t data[]; +} libusb_string_descriptor_t; + +typedef enum { + LIBUSB_PACKET_SIZE_BITS_8, + LIBUSB_PACKET_SIZE_BITS_16, + LIBUSB_PACKET_SIZE_BITS_32, + LIBUSB_PACKET_SIZE_BITS_64, +} libusb_packet_size_t; + +typedef enum { + LIBUSB_SPEED_HIGH = 0, + LIBUSB_SPEED_FULL = 1, + LIBUSB_SPEED_LOW = 2, +} libusb_speed_t; + +typedef struct __packed { + libusb_packet_size_t max_size : 2; + libusb_speed_t speed : 2; + uint8_t end_point : 4; + uint8_t device : 8; + libusb_transfer_t type : 2; + libusb_direction_t direction : 1; + uint16_t reserved : 13; +} libusb_pipe_address_t; + +typedef enum { + // usb requests + LIBUSB_DEVICE_REQUEST_GET_STATUS = 0, + LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE = 1, + LIBUSB_DEVICE_REQUEST_SET_FEATURE = 3, + LIBUSB_DEVICE_REQUEST_SET_ADDRESS = 5, + LIBUSB_DEVICE_REQUEST_GET_DESCRIPTOR = 6, + LIBUSB_DEVICE_REQUEST_SET_DESCRIPTOR = 7, + LIBUSB_DEVICE_REQUEST_GET_CONFIGURATION = 8, + LIBUSB_DEVICE_REQUEST_SET_CONFIGURATION = 9, + LIBUSB_DEVICE_REQUEST_GET_INTERFACE = 10, + LIBUSB_DEVICE_REQUEST_SET_INTERFACE = 11, + LIBUSB_DEVICE_REQUEST_SYNCH_FRAME = 12, + // hid requests + LIBUSB_DEVICE_REQUEST_GET_REPORT = 1, + LIBUSB_DEVICE_REQUEST_GET_IDLE = 2, + LIBUSB_DEVICE_REQUEST_GET_PROTOCOL = 3, + LIBUSB_DEVICE_REQUEST_SET_REPORT = 9, + LIBUSB_DEVICE_REQUEST_SET_IDLE = 10, + LIBUSB_DEVICE_REQUEST_SET_PROTOCOL = 11, +} libusb_device_request_enum_t; + +typedef struct __packed { + uint8_t type; + libusb_device_request_enum_t request : 8; + uint16_t value; + uint16_t index; + uint16_t length; +} libusb_device_request_t; + +// enable warnings again +#pragma GCC diagnostic pop #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c index ad0f4039..0df17034 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -17,7 +17,10 @@ * along with bolthur/kernel. If not, see . */ +#include +#include #include "../rpc.h" +#include "../../../../../libhcd.h" /** * @fn void rpc_submit_control_message(size_t, pid_t, size_t, size_t) @@ -29,9 +32,46 @@ */ void rpc_submit_control_message( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info -) { - STARTUP_PRINT( "Interrupt handler called\r\n" ) + ) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // extract data + hcd_submit_control_message_t* submit_control_message; + // handle invalid data size + if ( data_size - sizeof( vfs_ioctl_perform_request_t ) < sizeof( *submit_control_message ) ) { + error.status = -EINVAL; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + free( request ); + return; + } + // allocate space for pull_request + submit_control_message = ( hcd_submit_control_message_t* )request->container; + // calculate control message length + [[maybe_unused]] size_t submit_control_buffer_size = data_size - sizeof( vfs_ioctl_perform_request_t ) + - sizeof( *submit_control_message ); + /// FIXME: IMPLEMENT + // return data and finish with free + error.status = -ENOSYS; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + free( request ); } From ce3b172b9c1ed33b54d9afde24bff0fdc49bf411 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 08:01:17 +0200 Subject: [PATCH 006/144] - Started working on usbd server by creating empty rpc_init and usbd_init - Generated usb device structure used by usbd --- bolthur/kernel/rpc/generic.c | 4 +- bolthur/server/libhcd.h | 1 + bolthur/server/libusb.h | 63 +++++++++++++++++++++++++++++ bolthur/server/usb/usbd/Makefile.am | 4 +- bolthur/server/usb/usbd/main.c | 24 ++++++++++- bolthur/server/usb/usbd/rpc.h | 28 +++++++++++++ bolthur/server/usb/usbd/rpc/init.c | 32 +++++++++++++++ bolthur/server/usb/usbd/usbd.c | 30 ++++++++++++++ bolthur/server/usb/usbd/usbd.h | 25 ++++++++++++ 9 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 bolthur/server/usb/usbd/rpc.h create mode 100644 bolthur/server/usb/usbd/rpc/init.c create mode 100644 bolthur/server/usb/usbd/usbd.c create mode 100644 bolthur/server/usb/usbd/usbd.h diff --git a/bolthur/kernel/rpc/generic.c b/bolthur/kernel/rpc/generic.c index ce9af662..786af0ec 100644 --- a/bolthur/kernel/rpc/generic.c +++ b/bolthur/kernel/rpc/generic.c @@ -190,7 +190,7 @@ bool rpc_generic_setup_mailbox( task_process_t* proc ) { return false; } // map page temporarily - uintptr_t tmp_map = virt_map_temporary( proc->rpc_mailbox, PAGE_SIZE ); + const uintptr_t tmp_map = virt_map_temporary( proc->rpc_mailbox, PAGE_SIZE ); if ( 0 == tmp_map ) { // free mailbox again phys_free_page( proc->rpc_mailbox ); @@ -208,7 +208,7 @@ bool rpc_generic_setup_mailbox( task_process_t* proc ) { // unmap again virt_unmap_temporary( tmp_map, PAGE_SIZE ); // set address - uintptr_t tmp_addr = ROUND_UP_TO_FULL_PAGE( task_thread_current_thread->entry ); + const uintptr_t tmp_addr = ROUND_UP_TO_FULL_PAGE( task_thread_current_thread->entry ); // find free space proc->rpc_mailbox_virt = virt_find_free_page_range( proc->virtual_context, PAGE_SIZE, tmp_addr ); // handle no address found diff --git a/bolthur/server/libhcd.h b/bolthur/server/libhcd.h index 5e398580..d4573230 100644 --- a/bolthur/server/libhcd.h +++ b/bolthur/server/libhcd.h @@ -26,6 +26,7 @@ #define HCD_SUBMIT_CONTROL_MESSAGE RPC_CUSTOM_START typedef struct { + libusb_device_t device; libusb_pipe_address_t pipe_address; libusb_device_request_t request; uint8_t buffer[]; diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index f1ec8280..ac82fe54 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -20,6 +20,10 @@ #ifndef _LIBUSB_H #define _LIBUSB_H +#define MAX_CHILDREN_PER_DEVICE 10 +#define MAX_INTERFACES_PER_DEVICE 8 +#define MAX_ENDPOINTS_PER_DEVICE 16 + // disable a bunch of warnings necessary to build packed structures // for usb communication #pragma GCC diagnostic push @@ -267,6 +271,65 @@ typedef struct __packed { uint16_t length; } libusb_device_request_t; +typedef enum { + LIBUSB_DEVICE_STATUS_ATTACHED = 0, + LIBUSB_DEVICE_STATUS_POWERED = 1, + LIBUSB_DEVICE_STATUS_DEFAULT = 2, + LIBUSB_DEVICE_STATUS_ADDRESSED = 3, + LIBUSB_DEVICE_STATUS_CONFIGURED = 4, +} libusb_device_status_t; + +typedef enum { + LIBUSB_TRANSFER_ERROR_NO_ERROR = 0, + LIBUSB_TRANSFER_ERROR_STALL = 1 << 1, + LIBUSB_TRANSFER_ERROR_BUFFER_ERROR = 1 << 2, + LIBUSB_TRANSFER_ERROR_BABBLE = 1 << 3, + LIBUSB_TRANSFER_ERROR_NO_ACKNOWLEDGE = 1 << 4, + LIBUSB_TRANSFER_ERROR_CRC_ERROR = 1 << 5, + LIBUSB_TRANSFER_ERROR_BIT_ERROR = 1 << 6, + LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR = 1 << 7, + LIBUSB_TRANSFER_ERROR_AHB_ERROR = 1 << 8, + LIBUSB_TRANSFER_ERROR_NOT_YET_ERROR = 1 << 9, + LIBUSB_TRANSFER_ERROR_PROCESSING = 1 << 10, +} libusb_transfer_error_t; + +typedef struct { + uint32_t device_driver; + uint32_t data_size; +} libusb_driver_data_header; + +typedef struct libusb_device libusb_device_t; +typedef struct libusb_device { + uint32_t number; + + libusb_speed_t speed; + libusb_device_status_t status; + uint8_t configuration_index; + libusb_transfer_error_t error __aligned( 4 ); + + /** Handler for detaching the device. The device driver should not issue further requests to the device. */ + void ( *device_detached )( libusb_device_t* device ) __aligned( 4 ); + /** Handler for deallocation of the device. All memory in use by the device driver should be deallocated. */ + void ( *device_deallocate )( libusb_device_t* device ); + /** Handler for checking for changes to the USB device tree. Only hubs need handle with this. */ + void ( *device_check_for_change )( libusb_device_t* device ); + /** Handler for removing a child device from this device. Only hubs need handle with this. */ + void ( *device_child_detached )( libusb_device_t* device, libusb_device_t* child ); + /** Handler for reseting a child device of this device. Only hubs need handle with this. */ + int ( *device_child_reset )( libusb_device_t* device, libusb_device_t* child ); + /** Handler for reseting a child device of this device. Only hubs need handle with this. */ + int ( *device_check_connection )( libusb_device_t* device, libusb_device_t* child ); + + libusb_device_descriptor_t descriptor __aligned( 4 ); + libusb_configuration_descriptor_t configuration __aligned( 4 ); + libusb_interface_descriptor_t Interfaces[ MAX_INTERFACES_PER_DEVICE ] __aligned( 4 ); + libusb_endpoint_descriptor_t Endpoints[ MAX_INTERFACES_PER_DEVICE ][ MAX_ENDPOINTS_PER_DEVICE ] __aligned( 4 ); + libusb_device_t* parent __aligned( 4 ); + void *full_configuration; + libusb_driver_data_header* driver_data; + uint32_t last_transfer; +} libusb_device_t; + // enable warnings again #pragma GCC diagnostic pop diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index 30a03a44..2977c1e4 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -3,5 +3,7 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/usbd\" bin_PROGRAMS = usbd usbd_SOURCES = \ - main.c + rpc/init.c \ + main.c \ + usbd.c usbd_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index 3bf88504..1c5e333c 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -17,8 +17,11 @@ * along with bolthur/kernel. If not, see . */ +#include #include #include +#include "usbd.h" +#include "rpc.h" /** * @fn int main(int, char*[]) @@ -29,7 +32,24 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print something - STARTUP_PRINT( "usbd processing!\r\n" ) + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler" ); + return -1; + } + + // setup hcd interface + STARTUP_PRINT( "Setup usbd interface!\r\n" ) + const int result = usbd_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to init usbd: %s\r\n", strerror( result ) ); + return -1; + } + + while ( true ) { + __asm__ __volatile__( "nop" ); + } + return -1; } diff --git a/bolthur/server/usb/usbd/rpc.h b/bolthur/server/usb/usbd/rpc.h new file mode 100644 index 00000000..561839c5 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc.h @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +bool rpc_init( void ); + +#endif diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c new file mode 100644 index 00000000..36eab1e5 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +// local includes +#include "../rpc.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + return true; +} diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c new file mode 100644 index 00000000..a4755968 --- /dev/null +++ b/bolthur/server/usb/usbd/usbd.c @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "usbd.h" + +/** + * @fn int usbd_init(void) + * @brief Method to init usbd + * @return 0 on success, else errno code + */ +int usbd_init( void ) { + return ENOSYS; +} diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h new file mode 100644 index 00000000..f18d0898 --- /dev/null +++ b/bolthur/server/usb/usbd/usbd.h @@ -0,0 +1,25 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef USBD_H +#define USBD_H + +int usbd_init( void ); + +#endif From d589a4355ade664dcba4b91678f9f84821176979 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 17:36:19 +0200 Subject: [PATCH 007/144] - Added virt_flush_complete call before detaching shared memory to enforce cache drain - some ongoing const changes - Added define for hcd device path - Replaced magic string in hcd server by define - Adjusted message for hcd submit control message to expect it put into shared area - Created helpers to transfer packet size from number into type and vice versa - Created helper to translate usb speed into strings - Added hub structures to libusb - Extended libhcd by power registers and completed host port registers - Temporarily commented out dma for usb - Made fd_iomem non static since it is required in new root hub function - Added new dwhci function to write host port - Added dwhciroothub function necessary for root hub init - Revised submit_control_message rpc to map shared memory and perform root hub process if set - First iteration of usbd yet without enumeration of connected devices --- bolthur/kernel/syscall/memory.c | 10 +- bolthur/server/libhcd.h | 10 +- bolthur/server/libusb.h | 163 ++- bolthur/server/platform/raspi/libhcd.h | 14 +- .../server/platform/raspi/usb/hcd/Makefile.am | 1 + bolthur/server/platform/raspi/usb/hcd/dwhci.c | 63 +- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 3 + .../platform/raspi/usb/hcd/dwhciroothub.c | 541 ++++++++ .../platform/raspi/usb/hcd/dwhciroothub.h | 30 + bolthur/server/platform/raspi/usb/hcd/main.c | 2 +- .../usb/hcd/rpc/submit_control_message.c | 85 +- bolthur/server/usb/usbd/usbd.c | 1169 ++++++++++++++++- bolthur/server/usb/usbd/usbd.h | 18 + 13 files changed, 2081 insertions(+), 28 deletions(-) create mode 100644 bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c create mode 100644 bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h diff --git a/bolthur/kernel/syscall/memory.c b/bolthur/kernel/syscall/memory.c index 2469ecbd..0c605698 100644 --- a/bolthur/kernel/syscall/memory.c +++ b/bolthur/kernel/syscall/memory.c @@ -433,6 +433,8 @@ void syscall_memory_shared_detach( void* context ) { #if defined( PRINT_SYSCALL ) DEBUG_OUTPUT( "syscall_memory_shared_detach( %zu )\r\n", id ) #endif + // drain possible cached stuff by performing complete flush + virt_flush_complete(); // try to detach if ( ! shared_memory_detach( task_thread_current_thread->process, id ) ) { syscall_populate_error( context, ( size_t )-EIO ); @@ -456,7 +458,7 @@ void syscall_memory_shared_size( void* context ) { DEBUG_OUTPUT( "syscall_memory_shared_size( %zu )\r\n", id ) #endif // try to get size - size_t len = shared_memory_size( task_thread_current_thread->process, id ); + const size_t len = shared_memory_size( task_thread_current_thread->process, id ); if ( 0 == len ) { syscall_populate_error( context, ( size_t )-EINVAL ); return; @@ -486,8 +488,8 @@ void syscall_memory_translate_physical( void* context ) { ->process ->virtual_context; // get min and max address of context - uintptr_t min = virt_get_context_min_address( virtual_context ); - uintptr_t max = virt_get_context_max_address( virtual_context ); + const uintptr_t min = virt_get_context_min_address( virtual_context ); + const uintptr_t max = virt_get_context_max_address( virtual_context ); // ensure that address is in context if ( min > address @@ -502,7 +504,7 @@ void syscall_memory_translate_physical( void* context ) { return; } // get mapped address - uint64_t phys = virt_get_mapped_address_in_context( virtual_context, address ); + const uint64_t phys = virt_get_mapped_address_in_context( virtual_context, address ); // populate success syscall_populate_success( context, ( uintptr_t )phys + offset ); } diff --git a/bolthur/server/libhcd.h b/bolthur/server/libhcd.h index d4573230..ffa565c2 100644 --- a/bolthur/server/libhcd.h +++ b/bolthur/server/libhcd.h @@ -23,13 +23,21 @@ #include #include "libusb.h" +#define HCD_DEVICE_PATH "/dev/usb/hcd" + #define HCD_SUBMIT_CONTROL_MESSAGE RPC_CUSTOM_START +typedef struct { + size_t shm_id; +} hcd_submit_control_message_t; + typedef struct { libusb_device_t device; libusb_pipe_address_t pipe_address; libusb_device_request_t request; + size_t buffer_length; + size_t timeout; uint8_t buffer[]; -} hcd_submit_control_message_t; +} hcd_control_message_t; #endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index ac82fe54..2d5f5cd4 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -225,12 +225,66 @@ typedef enum { LIBUSB_PACKET_SIZE_BITS_64, } libusb_packet_size_t; +/** + * @brief Get packet size from number + * @param size + * @return + */ +[[maybe_unused]] static libusb_packet_size_t usb_packet_size_from_number( + const uint32_t size +) { + if (size <= 8) { + return LIBUSB_PACKET_SIZE_BITS_8; + } + if (size <= 16) { + return LIBUSB_PACKET_SIZE_BITS_16; + } + if (size <= 32) { + return LIBUSB_PACKET_SIZE_BITS_32; + } + return LIBUSB_PACKET_SIZE_BITS_64; +} + +/** + * @brief Transform size to number + * @param size + * @return + */ +[[maybe_unused]] static uint32_t usb_number_from_packet_size( + const libusb_packet_size_t size +) { + switch ( size ) { + case LIBUSB_PACKET_SIZE_BITS_8: return 8; + case LIBUSB_PACKET_SIZE_BITS_16: return 16; + case LIBUSB_PACKET_SIZE_BITS_32: return 32; + default: return 64; + } +} + typedef enum { LIBUSB_SPEED_HIGH = 0, LIBUSB_SPEED_FULL = 1, LIBUSB_SPEED_LOW = 2, } libusb_speed_t; +/** + * @brief Small static function to turn speed into string for printing purposes + * @param speed speed to translate + * @return translated speed + */ +[[maybe_unused]] static char* usb_speed_to_string( const libusb_speed_t speed ) { + if ( LIBUSB_SPEED_HIGH == speed ) { + return "480 Mb/s"; + } + if ( LIBUSB_SPEED_LOW == speed ) { + return "1.5 Mb/s"; + } + if ( LIBUSB_SPEED_FULL == speed ) { + return "12 Mb/s"; + } + return "Unknown Mb/s"; +} + typedef struct __packed { libusb_packet_size_t max_size : 2; libusb_speed_t speed : 2; @@ -305,6 +359,7 @@ typedef struct libusb_device { libusb_speed_t speed; libusb_device_status_t status; uint8_t configuration_index; + uint8_t port_number; libusb_transfer_error_t error __aligned( 4 ); /** Handler for detaching the device. The device driver should not issue further requests to the device. */ @@ -322,14 +377,118 @@ typedef struct libusb_device { libusb_device_descriptor_t descriptor __aligned( 4 ); libusb_configuration_descriptor_t configuration __aligned( 4 ); - libusb_interface_descriptor_t Interfaces[ MAX_INTERFACES_PER_DEVICE ] __aligned( 4 ); - libusb_endpoint_descriptor_t Endpoints[ MAX_INTERFACES_PER_DEVICE ][ MAX_ENDPOINTS_PER_DEVICE ] __aligned( 4 ); + libusb_interface_descriptor_t interfaces[ MAX_INTERFACES_PER_DEVICE ] __aligned( 4 ); + libusb_endpoint_descriptor_t endpoints[ MAX_INTERFACES_PER_DEVICE ][ MAX_ENDPOINTS_PER_DEVICE ] __aligned( 4 ); libusb_device_t* parent __aligned( 4 ); void *full_configuration; libusb_driver_data_header* driver_data; uint32_t last_transfer; + + // pointer to next usb device + libusb_device_t* next; + libusb_device_t* prev; } libusb_device_t; +typedef enum { + LIBUSB_HUB_PORT_CONTROL_GLOBAL = 0, + LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL = 1, +} libusb_hub_port_control_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type; + uint8_t port_count; + struct __packed { + libusb_hub_port_control_t power_switching_mode : 2; + bool compound : 1; + libusb_hub_port_control_t over_current_protection : 2; + uint8_t think_time : 2; + bool indicators : 1; + uint8_t reserved : 8; + } attributes; + uint8_t power_good_delay; + uint8_t maximum_hub_power; + uint8_t data[]; +} libusb_hub_descriptor_t; + +typedef struct __packed { + bool local_power : 1; + bool over_current : 1; + uint16_t reserved : 14; +} libusb_hub_status_t; + +typedef struct __packed { + bool local_power_changed : 1; + bool over_current_changed : 1; + uint16_t reserved : 14; +} libusb_hub_status_change_t; + +typedef struct __packed { + libusb_hub_status_t status; + libusb_hub_status_change_t change; +} libusb_hub_full_status_t; + +typedef struct __packed { + bool connected : 1; + bool enabled : 1; + bool suspended : 1; + bool over_current : 1; + bool reset : 1; + uint8_t reserved0 : 3; + bool power : 1; + bool low_speed_attached : 1; + bool high_speed_attached : 1; + bool test_mode : 1; + bool indicator_control : 1; + uint8_t reserved1 : 3; +} libusb_hub_port_status_t; + +typedef struct __packed { + bool connected_changed : 1; + bool enabled_changed : 1; + bool suspended_changed : 1; + bool over_current_changed : 1; + bool reset_changed : 1; + uint16_t reserved : 11; +} libusb_hub_port_status_change_t; + +typedef struct __packed { + libusb_hub_port_status_t status; + libusb_hub_port_status_change_t change; +} libusb_hub_port_full_status_t; + +typedef enum { + LIBUSB_HUB_PORT_FEATURE_CONNECTION = 0, + LIBUSB_HUB_PORT_FEATURE_ENABLE = 1, + LIBUSB_HUB_PORT_FEATURE_SUSPEND = 2, + LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT = 3, + LIBUSB_HUB_PORT_FEATURE_RESET = 4, + LIBUSB_HUB_PORT_FEATURE_POWER = 8, + LIBUSB_HUB_PORT_FEATURE_LOW_SPEED = 9, + LIBUSB_HUB_PORT_FEATURE_HIGH_SPEED = 10, + LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE = 16, + LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE = 17, + LIBUSB_HUB_PORT_FEATURE_SUSPENDED_CHANGE = 18, + LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE = 19, + LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE = 20, +} libusb_hub_port_feature_t; + +#define DEVICE_DRIVER_HUB 0x48554230 + +typedef struct { + libusb_driver_data_header header; + libusb_hub_full_status_t status; + libusb_hub_descriptor_t* descriptor; + uint32_t max_children; + libusb_hub_port_full_status_t port_status[ MAX_CHILDREN_PER_DEVICE ]; + libusb_device_t* children[ MAX_CHILDREN_PER_DEVICE ]; +} libusb_hub_device_t; + +typedef enum { + LIBUSB_HUB_FEATURE_POWER = 0, + LIBUSB_HUB_FEATURE_OVER_CURRENT = 1, +} libusb_hub_feature_t; + // enable warnings again #pragma GCC diagnostic pop diff --git a/bolthur/server/platform/raspi/libhcd.h b/bolthur/server/platform/raspi/libhcd.h index 43615978..3ceb90e6 100644 --- a/bolthur/server/platform/raspi/libhcd.h +++ b/bolthur/server/platform/raspi/libhcd.h @@ -126,9 +126,12 @@ #define HCD_DWHCI_HOST_PORT_ENABLE_CHANGED ( 1 << 3 ) #define HCD_DWHCI_HOST_PORT_OVERCURRENT ( 1 << 4 ) #define HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED ( 1 << 5 ) +#define HCD_DWHCI_HOST_PORT_RESUME ( 1 << 6 ) +#define HCD_DWHCI_HOST_PORT_SUSPEND ( 1 << 7 ) #define HCD_DWHCI_HOST_PORT_RESET ( 1 << 8 ) #define HCD_DWHCI_HOST_PORT_POWER ( 1 << 12 ) -#define HCD_DWHCI_HOST_PORT_SPEED( reg ) ( ( ( reg ) >> 17 ) & 3 ) +#define HCD_DWHCI_HOST_PORT_SPEED( reg ) ( ( ( reg ) >> 17 ) & 0x3 ) +#define HCD_DWHCI_HOST_PORT_TEST_CONTROL( reg ) ( ( ( reg ) >> 13 ) & 0xf ) #define HCD_DWHCI_HOST_PORT_SPEED_HIGH 0 #define HCD_DWHCI_HOST_PORT_SPEED_FULL 1 #define HCD_DWHCI_HOST_PORT_SPEED_LOW 2 @@ -145,5 +148,14 @@ #define HCD_DWHCI_CORE_INT_MASK_DISCONNECT ( 1 << 29 ) #define HCD_DWHCI_CORE_INT_MASK_SESS_REQ_INTR ( 1 << 30 ) #define HCD_DWHCI_CORE_INT_MASK_WKUP_INTR ( 1 << 31 ) +// power reg +#define HCD_DWHCI_POWER_REGISTER_STOP_P_CLOCK ( 1 << 0 ) +#define HCD_DWHCI_POWER_REGISTER_GATE_H_CLOCK ( 1 << 1 ) +#define HCD_DWHCI_POWER_REGISTER_POWER_CLAMP ( 1 << 2 ) +#define HCD_DWHCI_POWER_REGISTER_POWER_DOWN_MODULES ( 1 << 3 ) +#define HCD_DWHCI_POWER_REGISTER_PHY_SUSPENDED ( 1 << 4 ) +#define HCD_DWHCI_POWER_REGISTER_ENABLE_SLEEP_CLOCK_GATING ( 1 << 5 ) +#define HCD_DWHCI_POWER_REGISTER_PHY_SLEEPING ( 1 << 6 ) +#define HCD_DWHCI_POWER_REGISTER_DEEP_SLEEP ( 1 << 7 ) #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/Makefile.am b/bolthur/server/platform/raspi/usb/hcd/Makefile.am index c32eacac..e42eadf5 100644 --- a/bolthur/server/platform/raspi/usb/hcd/Makefile.am +++ b/bolthur/server/platform/raspi/usb/hcd/Makefile.am @@ -7,6 +7,7 @@ hcd_SOURCES = \ rpc/init.c \ rpc/submit_control_message.c \ dwhci.c \ + dwhciroothub.c \ main.c \ response.c \ util.c diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index d6c6c47a..40f26e3b 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -32,9 +32,9 @@ #include "../../libmailbox.h" /** - * @brief Static file descriptor for iomem operations + * @brief file descriptor for iomem operations */ -static int fd_iomem = -1; +int fd_iomem = -1; /** * @fn uint32_t dwhci_query_vendor(uint32_t*) @@ -858,7 +858,8 @@ response_t dwhci_init_core( void ) { // free sequence free( sequence ); // manipulate config - ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; + /// FIXME: ENABLE DMA AND WORK WITH INTERRUPTS + //ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES; ahb_cfg &= ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_MASK; // allocate sequence to write it back @@ -1170,6 +1171,60 @@ response_t dwhci_core_flush_rx_fifo( void ) { return HCD_RESPONSE_OK; } +/** + * @fn response_t dwhci_write_host_port(uint32_t) + * @brief Helper to write back host port value + * @param port + * @return + */ +response_t dwhci_write_host_port( uint32_t port ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Writing host port value %#"PRIx32"\r\n", port ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 1 ].value = port; + // perform request + const int ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; + +} + /** * @fn response_t dwhci_read_host_cfg(uint32_t*) * @brief Wrapper to read cfg @@ -1179,7 +1234,7 @@ response_t dwhci_core_flush_rx_fifo( void ) { response_t dwhci_read_host_port( uint32_t* port ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read usb host cfg\r\n" ) + STARTUP_PRINT( "Read host port\r\n" ) #endif // validate parameter if ( ! port ) { diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 5b5617f9..06f6eebc 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -25,6 +25,8 @@ #define DWHCI_ENABLE_DEBUG 1 +extern int fd_iomem; + response_t dwhci_query_vendor( uint32_t* destination ); response_t dwhci_power_on( void ); response_t dwhci_enable_global_interrupts( void ); @@ -38,6 +40,7 @@ response_t dwhci_init_core( void ); response_t dwhci_read_host_cfg( uint32_t* ); response_t dwhci_core_flush_tx_fifo( uint32_t ); response_t dwhci_core_flush_rx_fifo( void ); +response_t dwhci_write_host_port( uint32_t ); response_t dwhci_read_host_port( uint32_t* ); response_t dwhci_enable_host_interrupts( void ); response_t dwhci_init_host( void ); diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c new file mode 100644 index 00000000..eaa26775 --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c @@ -0,0 +1,541 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include +#include +#include "dwhci.h" +#include "dwhciroothub.h" + +#include + +#include "../../libhcd.h" +#include "../../libiomem.h" +#include "../../libperipheral.h" +#include "../../storage/sd/util.h" + +uint32_t dwhciroothub_root_hub_device_number = 0; + +// disable a bunch of warnings necessary to build packed structures +// for usb communication +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpacked" +#pragma GCC diagnostic ignored "-Wattributes" +#pragma GCC diagnostic ignored "-Wpedantic" + +static libusb_device_descriptor_t descriptor = { + .descriptor_length = 0x12, + .descriptor_type = LIBUSB_DESCRIPTOR_DEVICE, + .usb_version = 0x0200, + .class = LIBUSB_DEVICE_CLASS_HUB, + .subclass = 0, + .protocol = 0, + .max_packet_size0 = 0, + .vendor_id = 0, + .product_id = 0, + .version = 0x0100, + .manufacturer = 0, + .product = 1, + .serial_number = 0, + .configuration_count = 1, +}; + +struct { + libusb_configuration_descriptor_t configuration; + libusb_interface_descriptor_t interface; + libusb_endpoint_descriptor_t endpoint; +} __packed configuration_descriptor = { + .configuration = { + .descriptor_length = 9, + .descriptor_type = LIBUSB_DESCRIPTOR_CONFIGURATION, + .total_length = 0x19, + .interface_count = 1, + .configuration_value = 1, + .string_index = 0, + .attributes = { + .remote_wakeup = false, + .self_powered = true, + .reserved1 = 1, + }, + .maximum_power = 0, + }, + .interface = { + .descriptor_length = 9, + .descriptor_type = LIBUSB_DESCRIPTOR_INTERFACE, + .number = 0, + .alternate_setting = 0, + .endpoint_count = 1, + .class = LIBUSB_INTERFACE_CLASS_HUB, + .subclass = 0, + .protocol = 0, + .string_index = 0, + }, + .endpoint = { + .descriptor_length = 7, + .descriptor_type = LIBUSB_DESCRIPTOR_ENDPOINT, + .endpoint_address = { + .number = 1, + .direction = LIBUSB_DIRECTION_IN, + }, + .attributes = { + .transfer = LIBUSB_TRANSFER_INTERRUPT, + }, + .packet = { + .max_size = 8, + }, + .interval = 0xff, + }, +}; + +static libusb_string_descriptor_t string0 = { + .descriptor_length = 4, + .descriptor_type = LIBUSB_DESCRIPTOR_STRING, + .data = { + 0x0409 + }, +}; + +static libusb_string_descriptor_t string1 = { + .descriptor_length = sizeof( u"USB 2.0 Root Hub" ) + 2, + .descriptor_type = LIBUSB_DESCRIPTOR_STRING, + .data = u"USB 2.0 Root Hub", +}; + +static libusb_hub_descriptor_t hub_descriptor = { + .descriptor_length = 0x9, + .descriptor_type = LIBUSB_DESCRIPTOR_HUB, + .port_count = 1, + .attributes = { + .power_switching_mode = LIBUSB_HUB_PORT_CONTROL_GLOBAL, + .compound = false, + .over_current_protection = LIBUSB_HUB_PORT_CONTROL_GLOBAL, + .think_time = 0, + .indicators = false, + }, + .power_good_delay = 0, + .maximum_hub_power = 0, + .data = { 0x01, 0xff, }, +}; + +// enable warnings again +#pragma GCC diagnostic pop + +/** + * @fn int dwhciroothub_process(libusb_device_t*, libusb_pipe_address_t, void*, size_t, libusb_device_request_t*) + * @brief Process root hub request + * @param dev + * @param pipe + * @param buffer + * @param buffer_length + * @param request + * @return + */ +int dwhciroothub_process( + libusb_device_t* dev, + const libusb_pipe_address_t pipe, + void* buffer, + const size_t buffer_length, + libusb_device_request_t* request +) { + // set device to processing + dev->error = LIBUSB_TRANSFER_ERROR_PROCESSING; + // check for interrupt pipe on root hub => not supported + if ( LIBUSB_TRANSFER_INTERRUPT == pipe.type ) { + // debug output + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Root hub does not support irq pipes\r\n" ) + #endif + // set error + dev->error = LIBUSB_TRANSFER_ERROR_STALL; + // return success + return 0; + } + // variable for result + int result = 0; + uint32_t reply_length = 0; + response_t dwhci_result; + uint32_t host_port; + int ioctl_result; + size_t sequence_size; + iomem_mmio_entry_t* sequence; + // handle request + switch ( request->request ) { + case LIBUSB_DEVICE_REQUEST_GET_STATUS: + switch ( request->type ) { + case 0x80: // + { + const uint16_t val = 1; + memcpy(buffer, &val, sizeof( val ) ); + reply_length = 2; + } + break; + case 0x81: // interface + case 0x82: // endpoint + { + const uint16_t val = 1; + memcpy(buffer, &val, sizeof( val ) ); + reply_length = 2; + } + break; + case 0xa0: // class + { + const uint32_t val = 1; + memcpy(buffer, &val, sizeof( val ) ); + reply_length = 4; + } + break; + case 0xa3: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // push to local variable + libusb_hub_port_full_status_t status = { + .status = { + // populate response + .connected = host_port & HCD_DWHCI_HOST_PORT_CONNECT ? 1 : 0, + .enabled = host_port & HCD_DWHCI_HOST_PORT_ENABLE ? 1 : 0, + .suspended = host_port & HCD_DWHCI_HOST_PORT_SUSPEND ? 1 : 0, + .over_current = host_port & HCD_DWHCI_HOST_PORT_OVERCURRENT ? 1 : 0, + .reset = host_port & HCD_DWHCI_HOST_PORT_RESET ? 1 : 0, + .power = host_port & HCD_DWHCI_HOST_PORT_POWER ? 1 : 0, + .test_mode = HCD_DWHCI_HOST_PORT_TEST_CONTROL( host_port ) ? 1 : 0, + }, + .change = { + .connected_changed = host_port & HCD_DWHCI_HOST_PORT_CONNECT_CHANGED ? 1 : 0, + .enabled_changed = host_port & HCD_DWHCI_HOST_PORT_ENABLE_CHANGED ? 1 : 0, + .over_current_changed = host_port & HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED ? 1 : 0, + .reset_changed = true, + }, + }; + if ( LIBUSB_SPEED_HIGH == HCD_DWHCI_HOST_PORT_SPEED( host_port ) ) { + status.status.high_speed_attached = true; + } else if ( LIBUSB_SPEED_LOW == HCD_DWHCI_HOST_PORT_SPEED( host_port ) ) { + status.status.low_speed_attached = true; + } + // copy over to buffer + const uint32_t val = 0; + memcpy( buffer, &val, sizeof( val ) ); + memcpy( buffer, &status, sizeof( status ) ); + break; + default: + dev->error = LIBUSB_TRANSFER_ERROR_STALL; + } + break; + case LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE: + reply_length = 0; + switch ( request->type ) { + case 0x2: + case 0x20: + break; + case 0x23: + switch ( ( libusb_hub_port_feature_t)request->value ) { + case LIBUSB_HUB_PORT_FEATURE_ENABLE: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // set enable + host_port |= HCD_DWHCI_HOST_PORT_ENABLE; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_SUSPEND: + // allocate sequence + sequence = util_prepare_mmio_sequence( 7, &sequence_size ); + if ( ! sequence ) { + dev->error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; + break; + } + // prepare sequence + // clear power + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 0 ].value = 0; + // delay 10 milliseconds + sequence[ 1 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 10; // 5 according to specs + // read host port + sequence[ 2 ].type = IOMEM_MMIO_ACTION_READ_OR; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 2 ].value = HCD_DWHCI_HOST_PORT_RESUME; + // write host port with resume enabled + sequence[ 3 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 3 ].value = 0x40; + // delay 200 milliseconds + sequence[ 4 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 4 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 4 ].sleep = 200; // 100 according to specs + // read again host port + sequence[ 5 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 5 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 5 ].value = ( uint32_t )~( HCD_DWHCI_HOST_PORT_RESUME + | HCD_DWHCI_HOST_PORT_SUSPEND ); + // write back with suspend false + sequence[ 6 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 6 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 6 ].value = ( uint32_t )0xc0; + // execute sequence + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // free sequence + free( sequence ); + // handle ioctl error + if ( -1 == ioctl_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_POWER: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // reset power bit + host_port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_POWER; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // set connect changed + host_port |= HCD_DWHCI_HOST_PORT_CONNECT_CHANGED; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // set enable changed + host_port |= HCD_DWHCI_HOST_PORT_ENABLE_CHANGED; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // set over current changed + host_port |= HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + default: + } + break; + default: + result = EINVAL; + } + break; + case LIBUSB_DEVICE_REQUEST_SET_FEATURE: + switch ( request->type ) { + case 0x20: + break; + case 0x23: + switch ( ( libusb_hub_port_feature_t )request->value ) { + case LIBUSB_HUB_PORT_FEATURE_RESET: + // allocate sequence + sequence = util_prepare_mmio_sequence( 8, &sequence_size ); + if ( ! sequence ) { + dev->error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; + break; + } + // read power with and + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_POWER_REGISTER_ENABLE_SLEEP_CLOCK_GATING; + // write back power with disabled sleep clock and stop p clock + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_POWER_REGISTER_STOP_P_CLOCK; + // clear power + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 2 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 2 ].value = 0; + // read port + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 3 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_SUSPEND; + // write back power with enabled reset and power flag and disabled suspend flag + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 4 ].value = HCD_DWHCI_HOST_PORT_RESET | HCD_DWHCI_HOST_PORT_POWER; + // delay 200 milliseconds + sequence[ 5 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 5 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 5 ].sleep = 120; // 60 according to specs + // read port + sequence[ 6 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 6 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 6 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_RESET; + // write back previous read + sequence[ 7 ].type = IOMEM_MMIO_ACTION_WRITE_PREVIOUS_READ; + sequence[ 7 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + // execute sequence + ioctl_result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // free sequence + free( sequence ); + // handle ioctl error + if ( -1 == ioctl_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + case LIBUSB_HUB_PORT_FEATURE_POWER: + // read host port + dwhci_result = dwhci_read_host_port( &host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + // set over current changed + host_port |= HCD_DWHCI_HOST_PORT_POWER; + // write back host port + dwhci_result = dwhci_write_host_port( host_port ); + if ( HCD_RESPONSE_OK != dwhci_result ) { + dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + break; + } + break; + default: + break; + } + break; + default: + result = EINVAL; + } + break; + case LIBUSB_DEVICE_REQUEST_SET_ADDRESS: + reply_length = 0; + dwhciroothub_root_hub_device_number = request->value; + break; + case LIBUSB_DEVICE_REQUEST_GET_DESCRIPTOR: + switch ( request->type ) { + case 0x80: + switch ( ( libusb_descriptor_type_t )( ( request->value >> 8 ) & 0xFF ) ) { + case LIBUSB_DESCRIPTOR_DEVICE: + reply_length = ( uint32_t )fmin( sizeof( descriptor ), buffer_length ); + memcpy( buffer, &descriptor, reply_length ); + break; + case LIBUSB_DESCRIPTOR_CONFIGURATION: + reply_length = ( uint32_t )fmin( sizeof( configuration_descriptor ), buffer_length ); + memcpy( buffer, &configuration_descriptor, reply_length ); + break; + case LIBUSB_DESCRIPTOR_STRING: + switch ( request->value & 0xFF ) { + case 0: + reply_length = ( uint32_t )fmin( string0.descriptor_length, buffer_length ); + memcpy( buffer, &string0, reply_length ); + break; + case 1: + reply_length = ( uint32_t )fmin( string1.descriptor_length, buffer_length ); + memcpy( buffer, &string1, reply_length ); + break; + default: + reply_length = 0; + } + break; + default: + result = EINVAL; + } + break; + case 0xa0: + reply_length = ( uint32_t )fmin( hub_descriptor.descriptor_length, buffer_length ); + memcpy( buffer, &hub_descriptor, reply_length ); + break; + default: + result = EINVAL; + } + break; + case LIBUSB_DEVICE_REQUEST_GET_CONFIGURATION: + *( ( uint8_t* )buffer ) = 0x1; + reply_length = 1; + break; + case LIBUSB_DEVICE_REQUEST_SET_CONFIGURATION: + reply_length = 0; + break; + default: result = EINVAL; + } + // handle invalid argument + if ( EINVAL == result ) { + dev->error |= LIBUSB_TRANSFER_ERROR_STALL; + } + // strip out processing error + dev->error &= ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING; + // set last transfer + dev->last_transfer = reply_length; + // return success + return 0; +} diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h new file mode 100644 index 00000000..f0f42ffe --- /dev/null +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h @@ -0,0 +1,30 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _DWHCIROOTHUB +#define _DWHCIROOTHUB + +#include +#include "../../../../libusb.h" + +extern uint32_t dwhciroothub_root_hub_device_number; + +int dwhciroothub_process( libusb_device_t*, libusb_pipe_address_t, void*, size_t, libusb_device_request_t* ); + +#endif diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index 6a085097..a0468c6f 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -60,7 +60,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { STARTUP_PRINT( "Sending device to vfs\r\n" ) uint32_t device_info[] = { HCD_SUBMIT_CONTROL_MESSAGE, }; STARTUP_PRINT( "HCD_SUBMIT_CONTROL_MESSAGE = %d\r\n", HCD_SUBMIT_CONTROL_MESSAGE ) - if ( !dev_add_file( "/dev/usb/hcd", device_info, 1 ) ) { + if ( !dev_add_file( HCD_DEVICE_PATH, device_info, 1 ) ) { STARTUP_PRINT( "Unable to add dev hcd\r\n" ) return -1; } diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c index 0df17034..605eab0c 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -18,8 +18,11 @@ */ #include +#include #include #include "../rpc.h" +#include "../dwhci.h" +#include "../dwhciroothub.h" #include "../../../../../libhcd.h" /** @@ -55,23 +58,77 @@ void rpc_submit_control_message( bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } - // extract data - hcd_submit_control_message_t* submit_control_message; - // handle invalid data size - if ( data_size - sizeof( vfs_ioctl_perform_request_t ) < sizeof( *submit_control_message ) ) { - error.status = -EINVAL; + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const hcd_submit_control_message_t* submit_control_message = + ( hcd_submit_control_message_t* )request->container; + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( + submit_control_message->shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + // set error + error.status = -errno; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // transform shared memory into message + hcd_control_message_t* message = ( hcd_control_message_t* )shm_addr; + // handle root hub device + if ( dwhciroothub_root_hub_device_number == message->pipe_address.device ) { + // try to process root hub + const int result = dwhciroothub_process( + &message->device, + message->pipe_address, + message->buffer, + message->buffer_length, + &message->request + ); + // handle error + if ( result != 0 ) { + // set error + error.status = -result; + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + } else { + // set error + error.status = -ENOSYS; + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // free request + free( request ); + // return from rpc bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } - // allocate space for pull_request - submit_control_message = ( hcd_submit_control_message_t* )request->container; - // calculate control message length - [[maybe_unused]] size_t submit_control_buffer_size = data_size - sizeof( vfs_ioctl_perform_request_t ) - - sizeof( *submit_control_message ); - /// FIXME: IMPLEMENT - // return data and finish with free - error.status = -ENOSYS; - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + // populate status and just copy over data from request + response->status = 0; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory free( request ); + free( response ); } diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index a4755968..b9f460b6 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -17,8 +17,1142 @@ * along with bolthur/kernel. If not, see . */ +// system includes #include +#include +#include +#include +#include +#include +// local includes #include "usbd.h" +// driver includes +#include "../../libusb.h" +#include "../../libhcd.h" + +/** + * @brief Static file descriptor for hcd operations + */ +static int fd_hcd = -1; + +/** + * @brief Head of device list + */ +static libusb_device_t* head = nullptr; + +/** + * @brief Default timeout for control messages + */ +#define CONTROL_MESSAGE_TIMEOUT 10 + +/** + * @fn void usbd_deallocate_device(libusb_device_t*) + * @brief Wrapper to deallocate an usb device + * @param dev device to deallocate + */ +void usbd_deallocate_device( libusb_device_t* dev ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Deallocating device\r\n" ) + #endif + // handle invalid parameter + if ( ! dev ) { + return; + } + // detach callback + if ( dev->device_detached ) { + dev->device_detached( dev ); + } + // deallocate callback + if ( dev->device_deallocate ) { + dev->device_deallocate( dev ); + } + // child detach + if ( dev->parent && dev->parent->device_child_detached ) { + dev->parent->device_child_detached( dev->parent, dev ); + } + // remove from list + if ( + ( + LIBUSB_DEVICE_STATUS_ADDRESSED == dev->status + || LIBUSB_DEVICE_STATUS_CONFIGURED == dev->status + ) && ( + dev->prev + || dev->next + ) + ) { + libusb_device_t* next = dev->next; + // set next of previous element if set + if ( dev->prev ) { + dev->prev->next = dev->next; + } + // set previous of next element if set + if ( dev->next ) { + dev->next->prev = dev->prev; + } + // handle root element + if ( head == dev ) { + head = next; + } + } + // free up full configuration + if ( dev->full_configuration ) { + free( dev->full_configuration ); + } + // free up device + free( dev ); +} + +/** + * @fn int usbd_allocate_device(libusb_device_t**, bool) + * @brief Wrapper to allocate a device + * @param dev + * @param insert_head + * @return + */ +int usbd_allocate_device( libusb_device_t** dev, bool insert_head ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Allocating device\r\n" ) + #endif + // validate parameter + if ( ! dev ) { + return EINVAL; + } + // allocate device + *dev = malloc( sizeof( libusb_device_t ) ); + // handle error + if ( ! *dev ) { + return ENOMEM; + } + // clear out everything + memset( *dev, 0, sizeof( libusb_device_t ) ); + // push into list + if ( ! insert_head ) { + // space for number + uint32_t number = 0; + libusb_device_t* current = head; + libusb_device_t* prev = head; + // loop until end + while ( current ) { + // increment number + number++; + // save previous + prev = current; + // go to next + current = current->next; + } + // populate number + ( *dev )->number = number + 1; + // insert into list + if ( prev ) { + prev->next = *dev; + ( *dev )->prev = prev; + } else { + head = *dev; + } + } else { + // root number + ( *dev )->number = 1; + // insert as first element + if ( ! head ) { + head = *dev; + } else { + // set previous of head + head->prev = *dev; + // set next of device + ( *dev )->next = head; + // overwrite head + head = *dev; + } + } + // populate rest of attributes + ( *dev )->status = LIBUSB_DEVICE_STATUS_ATTACHED; + ( *dev )->error = LIBUSB_TRANSFER_ERROR_NO_ERROR; + ( *dev )->port_number = 0; + ( *dev )->parent = nullptr; + ( *dev )->driver_data = nullptr; + ( *dev )->full_configuration = nullptr; + ( *dev )->configuration_index = 0xff; + ( *dev )->device_deallocate = nullptr; + ( *dev )->device_detached = nullptr; + ( *dev )->device_check_connection = nullptr; + ( *dev )->device_check_for_change = nullptr; + ( *dev )->device_child_detached = nullptr; + ( *dev )->device_child_reset = nullptr; + // return success + return 0; +} + +/** + * @fn int usbd_control_message(const libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t); + * @brief Wrapper to perform usbd control message + * @param dev + * @param pipe + * @param buffer + * @param buffer_length + * @param request + * @param timeout + * @return + */ +int usbd_control_message( + libusb_device_t* dev, + const libusb_pipe_address_t pipe, + void* buffer, + const size_t buffer_length, + const libusb_device_request_t* request, + const size_t timeout +) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "firing hcd control message\r\n" ) + #endif + // allocate shared memory + const size_t data_size = sizeof ( hcd_control_message_t ) + buffer_length + 1; + const size_t shm_id = _syscall_memory_shared_create( data_size ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + return e; + } + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + return e; + } + hcd_control_message_t* message = ( hcd_control_message_t* )shm_addr; + // populate real message in shared memory + memcpy( &message->device, dev, sizeof( libusb_device_t ) ); + memcpy( &message->pipe_address, &pipe, sizeof( pipe ) ); + memcpy( &message->request, request, sizeof( *request ) ); + message->buffer_length = buffer_length; + message->timeout = timeout; + if ( LIBUSB_DIRECTION_OUT == pipe.direction && buffer ) { + memcpy( &message->buffer, buffer, buffer_length ); + } + // allocate request + hcd_submit_control_message_t* control_request = malloc( sizeof( *control_request ) ); + if ( ! control_request ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return error + return ENOMEM; + } + // clear out everything + memset( control_request, 0, sizeof( *control_request ) ); + // populate shm_id + control_request->shm_id = shm_id; + // perform request + int result = ioctl( + fd_hcd, + IOCTL_BUILD_REQUEST( + HCD_SUBMIT_CONTROL_MESSAGE, + sizeof( *control_request ), + IOCTL_RDWR + ), + control_request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( control_request ); + // return eio + return EIO; + } + // response is equal to input + if ( message->device.error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Message to %s timeout reached\r\n", usbd_get_description( dev ) ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control_request + free( control_request ); + // return timeout + return ETIMEDOUT; + } + // handle error + if ( message->device.error & ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING ) { + // handle check for connection + if ( dev->parent && dev->parent->device_check_connection ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Verifying %s is still connected\r\n", usbd_get_description( dev ) ) + #endif + // check connection + result = dev->parent->device_check_connection( dev->parent, ( libusb_device_t* )dev ); + // handle error + if ( 0 != result ) { + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control_request + free( control_request ); + // return no link + return ENOLINK; + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "%s is still connected\r\n", usbd_get_description( dev ) ) + #endif + // set result to error + result = EIO; + } + } + // copy over data + if ( LIBUSB_DIRECTION_IN == pipe.direction && buffer ) { + memcpy( buffer, message->buffer, buffer_length ); + } + // copy over static fields into device populated via shared memory + dev->error = message->device.error; + dev->last_transfer = message->device.last_transfer; + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control message + free( control_request ); + // return result + return result; +} + +/** + * @fn int usbd_get_descriptor(libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t); + * @brief Get usb descriptor + * @param dev + * @param type + * @param index + * @param lang_id + * @param buffer + * @param buffer_length + * @param minimum_length + * @param recipient + * @return + */ +int usbd_get_descriptor( + libusb_device_t* dev, + const libusb_descriptor_type_t type, + const uint8_t index, + const uint16_t lang_id, + void* buffer, + const size_t buffer_length, + const size_t minimum_length, + const uint8_t recipient +) { + // perform control message + const int result = usbd_control_message( + dev, + (libusb_pipe_address_t) { + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_IN, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ) + }, + buffer, + buffer_length, + & ( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_DESCRIPTOR, + .type = 0x80 | recipient, + .value = ( uint16_t )type << 8 | index, + .index = lang_id, + .length = ( uint16_t )buffer_length + }, + CONTROL_MESSAGE_TIMEOUT + ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get descriptor: %#x:%#"PRIx8" for device: %s. Result: %s\r\n", + type, index, usbd_get_description( dev ), strerror( result ) ) + #endif + // return result + return result; + } + // handle not enough transferred + if ( dev->last_transfer < minimum_length ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unexpectedly short descriptor (%"PRIu32"/%zu) %#x:%#"PRIx8" for device %s. Result: %#x\r\n", + dev->last_transfer, minimum_length, type, index, usbd_get_description( dev ), result ) + #endif + // return protocol error + return EPROTO; + } + // return success + return 0; +} + +/** + * @fn int usbd_get_string(libusb_device_t*, uint8_t, uint16_t, void*, size_t) + * @brief Get usb string + * @param dev + * @param string_index + * @param lang_id + * @param buffer + * @param buffer_length + * @return + */ +int usbd_get_string( + libusb_device_t* dev, + const uint8_t string_index, + const uint16_t lang_id, + void* buffer, + const size_t buffer_length +) { + for ( size_t i = 0; i < 3; i++ ) { + // fetch descriptor + const int result = usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_STRING, string_index, lang_id, buffer, + buffer_length, buffer_length, 0 ); + // handle success + if ( 0 == result ) { + return 0; + } + } + // return error + return ETIMEDOUT; +} + +/** + * @fn int usbd_read_string_lang(libusb_device_t*, uint8_t, uint16_t, void*, size_t) + * @brief Get usb string lang + * @param dev + * @param string_index + * @param lang_id + * @param buffer + * @param buffer_length + * @return + */ +int usbd_read_string_lang( + libusb_device_t* dev, + const uint8_t string_index, + const uint16_t lang_id, + void* buffer, + const size_t buffer_length +) { + // get string length + const int result = usbd_get_string( dev, string_index, lang_id, buffer, + ( size_t )fmin( 2, buffer_length ) ); + // handle error + if ( 0 != result ) { + return result; + } + // read string + return usbd_get_string( + dev, string_index, lang_id, buffer, + ( size_t )fmin( ( ( uint8_t* )buffer )[ 0 ], buffer_length ) ); +} + +/** + * @fn int usbd_read_string(libusb_device_t*, uint8_t, void*, size_t) + * @brief Read usb string + * @param dev + * @param string_index + * @param buffer + * @param buffer_length + * @return + */ +int usbd_read_string( + libusb_device_t* dev, + const uint8_t string_index, + void* buffer, + const size_t buffer_length +) { + // validate parameter + if ( ! buffer || ! string_index ) { + return EINVAL; + } + // space for lang ids + uint16_t lang_id[ 2 ]; + // read lang + int result = usbd_read_string_lang( dev, 0, 0, &lang_id, 4 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Error getting languages for %s: %s\r\n", + usbd_get_description( dev ), strerror( result ) ) + #endif + // return result + return result; + } + // handle invalid transfer + if ( dev->last_transfer < 4 ) { + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unexpectedly short language list from %s\r\n", + usbd_get_description( dev ) ) + #endif + // return error + return EPROTO; + } + // transform buffer + libusb_string_descriptor_t* descriptor = ( libusb_string_descriptor_t* )buffer; + if ( ! descriptor ) { + return ENOMEM; + } + // read string again + result = usbd_read_string_lang( dev, string_index, lang_id[ 1 ], descriptor, buffer_length ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Error getting languages for %s: %s\r\n", + usbd_get_description( dev ), strerror( result ) ) + #endif + // return error + return result; + } + // cache descriptor length + const uint8_t descriptor_length = descriptor->descriptor_length; + // translate data into buffer + uint8_t i; + for ( i = 0; i < ( descriptor_length - 2 ) >> 2; i++ ) { + ( ( uint8_t* )buffer )[ i ] = descriptor->data[ i ] > 0xff + ? '?' : ( uint8_t )descriptor->data[ i ]; + } + // add null termination + if ( i < buffer_length ) { + ( ( uint8_t* )buffer)[ i++ ] = '\0'; + } + // return success + return 0; +} + +/** + * @fn int usbd_read_device_descriptor(libusb_device_t*) + * @brief Read usb device descriptor + * @param dev + * @return + */ +int usbd_read_device_descriptor( libusb_device_t* dev ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Read device descriptor\r\n" ) + #endif + + if ( LIBUSB_SPEED_LOW == dev->speed ) { + // set max packet size + dev->descriptor.max_packet_size0 = 8; + // get usb descriptor + const int result = usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_DEVICE, 0, 0, + ( void* )&dev->descriptor, + sizeof( dev->descriptor ), 8, 0 ); + // handle error + if ( 0 != result ) { + return result; + } + // handle fully transferred + if ( dev->last_transfer == sizeof( libusb_device_descriptor_t ) ) { + return result; + } + // read again + return usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_DEVICE, 0, 0, + ( void* )&dev->descriptor, sizeof( dev->descriptor ), + sizeof( dev->descriptor ), 0 ); + } + + if ( LIBUSB_SPEED_FULL == dev->speed ) { + // set packet size + dev->descriptor.max_packet_size0 = 64; + // get usb descriptor + const int result = usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_DEVICE, 0, 0, + ( void* )&dev->descriptor, + sizeof( dev->descriptor ), 8, 0 ); + // handle error + if ( 0 != result ) { + return result; + } + // handle fully transferred + if ( dev->last_transfer == sizeof( libusb_device_descriptor_t ) ) { + return result; + } + // read again + return usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_DEVICE, 0, 0, + ( void* )&dev->descriptor, sizeof( dev->descriptor ), + sizeof( dev->descriptor ), 0 ); + } + + // set packet size + dev->descriptor.max_packet_size0 = 64; + return usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_DEVICE, 0, 0, + ( void* )&dev->descriptor, sizeof( dev->descriptor ), + sizeof( dev->descriptor ), 0 ); +} + +/** + * @fn int usbd_set_address(libusb_device_t*, const uint8_t) + * @brief Set usb device address + * @param dev + * @param address + * @return + */ +int usbd_set_address( libusb_device_t* dev, const uint8_t address ) { + // validate + if ( LIBUSB_DEVICE_STATUS_DEFAULT != dev->status ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Illegal attempt to configure device %s with status %d\r\n", + usbd_get_description( dev ), dev->status ) + #endif + // return error + return EINVAL; + } + // perform control message + const int result = usbd_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = 0, + .direction = LIBUSB_DIRECTION_OUT, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + NULL, + 0, + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_SET_ADDRESS, + .type = 0, + .value = address, + }, + CONTROL_MESSAGE_TIMEOUT + ); + // handle error + if ( 0 != result ) { + return result; + } + // MicroDelay(10000); // Allows the address to propagate. + // populate address and status + dev->number = address; + dev->status = LIBUSB_DEVICE_STATUS_ADDRESSED; + // return success + return 0; +} + +/** + * @fn int usbd_set_configuration(libusb_device_t*, const uint8_t) + * @brief Set usb device configuration + * @param dev + * @param configuration + * @return + */ +int usbd_set_configuration( libusb_device_t* dev, const uint8_t configuration ) { + // validate + if ( LIBUSB_DEVICE_STATUS_ADDRESSED != dev->status ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Illegal attempt to configure device %s with status %d\r\n", + usbd_get_description( dev ), dev->status ) + #endif + // return error + return EINVAL; + } + + // perform control message + const int result = usbd_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_OUT, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + NULL, + 0, + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_SET_CONFIGURATION, + .type = 0, + .value = configuration, + }, + CONTROL_MESSAGE_TIMEOUT + ); + // handle error + if ( 0 != result ) { + return result; + } + // populate configuration index and status + dev->configuration_index = configuration; + dev->status = LIBUSB_DEVICE_STATUS_CONFIGURED; + // return success + return 0; +} + +/** + * @fn int usbd_configure(libusb_device_t*, uint8_t) + * @brief Configure usb device + * @param dev + * @param configuration + * @return + */ +int usbd_configure( libusb_device_t* dev, uint8_t configuration ) { + // validate + if ( LIBUSB_DEVICE_STATUS_ADDRESSED != dev->status ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Illegal attempt to configure device %s with status %d\r\n", + usbd_get_description( dev ), dev->status ) + #endif + // return error + return EINVAL; + } + // get configuration + int result = usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_CONFIGURATION, configuration, 0, + ( void* )&dev->configuration, sizeof( dev->configuration ), + sizeof( dev->configuration ), 0 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to retrieve configuration descriptor %#"PRIx8" for device %s\r\n", + configuration, usbd_get_description( dev ) ) + #endif + // return error + return result; + } + // allocate full descriptor + void* full_descriptor = malloc( dev->configuration.total_length ); + if ( ! full_descriptor ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to allocate full descriptor for device %s\r\n", + usbd_get_description( dev ) ) + #endif + // return error + return ENOMEM; + } + // get descriptor + result = usbd_get_descriptor( + dev, LIBUSB_DESCRIPTOR_CONFIGURATION, configuration, 0, + full_descriptor, dev->configuration.total_length, + dev->configuration.total_length, 0 ); + // handle error + if ( 0 != result ) { + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to retrieve full configuration descriptor %#"PRIx8" for device %s\r\n", + configuration, usbd_get_description( dev ) ) + #endif + // free memory again + free( full_descriptor ); + // return result + return result; + } + // populate configuration + dev->configuration_index = configuration; + // overwrite configuration with value we read + configuration = dev->configuration.configuration_value; + // prepare variables for extraction + libusb_descriptor_header_t* header = full_descriptor; + uint32_t last_interface = MAX_INTERFACES_PER_DEVICE; + uint32_t last_endpoint = MAX_ENDPOINTS_PER_DEVICE; + bool is_alternate = false; + bool looping = true; + // loop through stuff and read interfaces + for ( + header = ( libusb_descriptor_header_t* )( ( uint8_t* )header + header->descriptor_length ); + looping && ( ( uintptr_t )header - ( uintptr_t )full_descriptor ) < dev->configuration.total_length; + header = ( libusb_descriptor_header_t* )( ( uint8_t* )header + header->descriptor_length ) + ) { + switch ( header->descriptor_type ) { + case LIBUSB_DESCRIPTOR_INTERFACE: + const libusb_interface_descriptor_t* interface = ( libusb_interface_descriptor_t* )header; + if ( last_interface != interface->number ) { + // set last interface + last_interface = interface->number; + // copy over data + memcpy( + ( void* )&dev->interfaces[ last_interface ], + interface, sizeof( *interface ) ); + // reset last endpoint + last_endpoint = 0; + // set alternate to false + is_alternate = false; + } else { + // toggle alternate to true + is_alternate = true; + } + // we're done + break; + case LIBUSB_DESCRIPTOR_ENDPOINT: + if ( is_alternate ) { + break; + } + if ( + last_interface == MAX_INTERFACES_PER_DEVICE + || last_endpoint >= dev->interfaces[ last_interface ].endpoint_count + ) { + // debug output + #if defined (USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unexpected endpoint descriptor in %s.Interface: %"PRIu32, + usbd_get_description( dev ), last_interface + 1 ) + #endif + // stop here + break; + } + // get endpoint + const libusb_endpoint_descriptor_t* endpoint = ( libusb_endpoint_descriptor_t* )header; + // copy over content + memcpy( + ( void* )&dev->endpoints[ last_interface ][ last_endpoint++ ], + endpoint, sizeof( *endpoint ) ); + // we're done + break; + default: + if ( header->descriptor_length == 0 ) { + looping = false; + continue; + } + break; + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Descriptor %"PRIu8" length %"PRIu8", interface %"PRIu32"\r\n", + header->descriptor_type, header->descriptor_length, last_interface ) + #endif + } + // configure usb device + result = usbd_set_configuration( dev, configuration ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to set configuration for device %s: %s\r\n", + usbd_get_description( dev ), strerror( result ) ) + #endif + // free memory again + free( full_descriptor ); + // return result + return result; + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( + "%s configuration %"PRIu8", class: %"PRIu8", subclass: %"PRIu8"\r\n", + usbd_get_description( dev ), configuration, + dev->interfaces[ 0 ].class, dev->interfaces[ 0 ].subclass ) + #endif + // populate full descriptor + dev->full_configuration = full_descriptor; + // return success + return 0; +} + +/** + * @fn const char* usbd_get_description(const libusb_device_t*) + * @brief Get usb description + * @param dev + * @return + */ +const char* usbd_get_description( const libusb_device_t* dev ) { + if ( LIBUSB_DEVICE_STATUS_ATTACHED == dev->status ) { + return "New device (not ready)"; + } + if ( LIBUSB_DEVICE_STATUS_POWERED == dev->status ) { + return "Unknown device (not ready)"; + } + if ( dev == head ) { + return "USB root hub"; + } + + switch ( dev->descriptor.class ) { + // hubs + case LIBUSB_DEVICE_CLASS_HUB: + if ( dev->descriptor.usb_version == 0x210 ) { + return "USB 2.1 Hub"; + } + if ( dev->descriptor.usb_version == 0x200 ) { + return "USB 2.0 Hub"; + } + if ( dev->descriptor.usb_version == 0x110 ) { + return "USB 1.1 Hub"; + } + if ( dev->descriptor.usb_version == 0x100 ) { + return "USB 1.0 Hub"; + } + return "USB Hub"; + // vendor specific + case LIBUSB_DEVICE_CLASS_VENDOR_SPECIFIC: + if ( dev->descriptor.vendor_id == 0x424 && dev->descriptor.product_id == 0xec00 ) { + return "SMSC LAN9512"; + } + return "Vendor specific"; + // interfaces + case LIBUSB_DEVICE_CLASS_IN_INTERFACE: + if ( LIBUSB_DEVICE_STATUS_CONFIGURED == dev->status ) { + switch ( dev->interfaces[ 0 ].class ) { + case LIBUSB_INTERFACE_CLASS_AUDIO: return "USB Audio device"; + case LIBUSB_INTERFACE_CLASS_COMMUNICATIONS: return "USB CDC device"; + case LIBUSB_INTERFACE_CLASS_HID: + switch ( dev->interfaces[ 0 ].protocol ) { + case 1: return "USB Keyboard"; + case 2: return "USB Mouse"; + default: return "USB HID"; + } + case LIBUSB_INTERFACE_CLASS_PHYSICAL: return "USB Physical device"; + case LIBUSB_INTERFACE_CLASS_IMAGE: return "USB Imaging device"; + case LIBUSB_INTERFACE_CLASS_PRINTER: return "USB Printer device"; + case LIBUSB_INTERFACE_CLASS_MASS_STORAGE: return "USB Mass storage device"; + case LIBUSB_INTERFACE_CLASS_HUB: + if ( dev->descriptor.usb_version == 0x210 ) { + return "USB 2.1 Hub"; + } + if ( dev->descriptor.usb_version == 0x200 ) { + return "USB 2.0 Hub"; + } + if ( dev->descriptor.usb_version == 0x110 ) { + return "USB 1.1 Hub"; + } + if ( dev->descriptor.usb_version == 0x100 ) { + return "USB 1.0 Hub"; + } + return "USB Hub"; + case LIBUSB_INTERFACE_CLASS_CDC_DATA: return "USB CDC device"; + case LIBUSB_INTERFACE_CLASS_SMART_CARD: return "USB Smart card"; + case LIBUSB_INTERFACE_CLASS_CONTENT_SECURITY: return "USB Content security"; + case LIBUSB_INTERFACE_CLASS_VIDEO: return "USB Video"; + case LIBUSB_INTERFACE_CLASS_PERSONAL_HEALTHCARE: return "USB Personal health care"; + case LIBUSB_INTERFACE_CLASS_AUDIO_VIDEO: return "USB AV device"; + case LIBUSB_INTERFACE_CLASS_DIAGNOSTIC_DEVICE: return "USB Diagnostic device"; + case LIBUSB_INTERFACE_CLASS_WIRELESS_CONTROLLER: return "USB Wireless controller"; + case LIBUSB_INTERFACE_CLASS_MISCELLANEOUS: return "USB Miscellaneous device"; + case LIBUSB_DEVICE_CLASS_VENDOR_SPECIFIC: return "Vendor Specific"; + default: return "Generic device"; + } + } else { + return "Unconfigured device"; + } + default: return "Generic device"; + } +} + +/** + * @fn int usbd_attach_device(libusb_device_t*) + * @brief Wrapper to attach device + * @param dev device to attach + * @return 0 on success else errno + */ +int usbd_attach_device( libusb_device_t* dev ) { + // cache device number + const uint8_t address = ( uint8_t )dev->number; + // reset device number + dev->number = 0; + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Scanning %"PRIu8". %s.\r\n", address, usb_speed_to_string( dev->speed ) ) + #endif + // read device descriptor + int result = usbd_read_device_descriptor( dev ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Reading device descriptor failed: %s\r\n", strerror( result ) ) + #endif + // restore number + dev->number = address; + // return result + return result; + } + // set device status to default + dev->status = LIBUSB_DEVICE_STATUS_DEFAULT; + // handle parent set with device child reset + if ( dev->parent && dev->parent->device_child_reset ) { + // perform child reset + result = dev->parent->device_child_reset(dev->parent, dev ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Reset child device failed: %s\r\n", strerror( result ) ) + #endif + // restore number + dev->number = address; + // return result + return result; + } + } + // set address + result = usbd_set_address( dev, address ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Set address failed: %s\r\n", strerror( result ) ) + #endif + // restore number + dev->number = address; + // return result + return result; + } + // overwrite number again + dev->number = address; + // re-read device descriptor + result = usbd_read_device_descriptor( dev ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Reading device descriptor failed: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Attach Device %s. Address:%"PRIu8" Class:%d Subclass:%"PRIu8 + " USB:%"PRIx16".%"PRIx16". %"PRIu8" configurations, %"PRIu8" interfaces.\n", + usbd_get_description( dev ), address, dev->descriptor.class, dev->descriptor.subclass, + dev->descriptor.usb_version >> 8, dev->descriptor.usb_version >> 4, + dev->descriptor.configuration_count, dev->configuration.interface_count ) + STARTUP_PRINT( "Device Attached: %s\r\n", usbd_get_description( dev ) ) + #endif + // allocate buffer for printing + char* buffer = malloc( 1024 ); + // read product if set + if ( dev->descriptor.product && buffer ) { + result = usbd_read_string( dev, dev->descriptor.product, buffer, 1024 ); + if ( 0 == result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "-Product: %s\r\n", buffer ) + #endif + } + } + // read manufacturer + if ( dev->descriptor.manufacturer && buffer ) { + result = usbd_read_string( dev, dev->descriptor.manufacturer, buffer, 1024 ); + if ( 0 == result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "-Manufacturer: %s\r\n", buffer ) + #endif + } + } + // read serial number + if ( dev->descriptor.serial_number && buffer ) { + result = usbd_read_string( dev, dev->descriptor.serial_number, buffer, 1024 ); + if ( 0 == result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "-Serial number: %s\r\n", buffer ) + #endif + } + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT("-VIID:PID: %"PRIx16":%"PRIx16" v%"PRId16":%"PRIx16"\r\n", + dev->descriptor.vendor_id, dev->descriptor.product_id, + dev->descriptor.version >> 8, dev->descriptor.version & 0xff ) + #endif + // configure device + result = usbd_configure( dev, 0 ); + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Configure failed: %s\r\n", strerror( result ) ) + #endif + // return error + return result; + } + + // print configuration + if ( dev->configuration.string_index && buffer ) { + result = usbd_read_string( dev, dev->configuration.string_index, buffer, 1024 ); + if ( 0 == result ) { + // debug ouptut + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "-Configuration: %s\r\n", buffer ) + #endif + } + } + // free buffer again + if ( buffer ) { + free( buffer ); + } + /// FIXME: ENUMERATE ALL DEVICES + // return success + return 0; +} + +/** + * @fn int usbd_attach_root_hub(void) + * @brief Wrapper to attach root hub + * @return 0 on success else errno + */ +int usbd_attach_root_hub( void ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Attaching root hob\r\n" ) + #endif + // space for root hub + libusb_device_t* root_hub = nullptr; + // handle existing by freeing up + if ( head && 1 == head->number ) { + usbd_deallocate_device( head ); + } + // allocate device + int result = usbd_allocate_device( &root_hub, true ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Allocating root hub failed: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // set device to powered on + root_hub->status = LIBUSB_DEVICE_STATUS_POWERED; + // attach usb device + result = usbd_attach_device( root_hub ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Attaching root hub failed: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // return success + return 0; +} /** * @fn int usbd_init(void) @@ -26,5 +1160,38 @@ * @return 0 on success, else errno code */ int usbd_init( void ) { - return ENOSYS; + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Init usdb\r\n" ) + #endif + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Opening device %s\r\n", HCD_DEVICE_PATH ) + #endif + // open file descriptor for mmio actions + if ( -1 == ( fd_hcd = open( HCD_DEVICE_PATH, O_RDWR ) ) ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to open device\r\n" ) + #endif + // return error response + return ENXIO; + } + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Attaching root hub\r\n" ) + #endif + // try to attach root hub + const int result = usbd_attach_root_hub(); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Allocating root hub failed: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // return success + return 0; } diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h index f18d0898..8c68d5cb 100644 --- a/bolthur/server/usb/usbd/usbd.h +++ b/bolthur/server/usb/usbd/usbd.h @@ -20,6 +20,24 @@ #ifndef USBD_H #define USBD_H +#include "../../libusb.h" + +#define USBD_ENABLE_DEBUG 1 + +void usbd_deallocate_device( libusb_device_t* ); +int usbd_allocate_device( libusb_device_t**, bool ); +int usbd_control_message( libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t ); +int usbd_get_descriptor( libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t ); +int usbd_get_string( libusb_device_t*, uint8_t, uint16_t, void*, size_t ); +int usbd_read_string_lang( libusb_device_t*, uint8_t, uint16_t, void*, size_t ); +int usbd_read_string( libusb_device_t*, uint8_t, void*, size_t ); +int usbd_read_device_descriptor( libusb_device_t* ); +int usbd_set_address( libusb_device_t*, uint8_t ); +int usbd_set_configuration( libusb_device_t*, uint8_t ); +int usbd_configure( libusb_device_t*, uint8_t ); +const char* usbd_get_description( const libusb_device_t* ); +int usbd_attach_device( libusb_device_t* ); +int usbd_attach_root_hub( void ); int usbd_init( void ); #endif From 01dd6fd013c10057cf8248fc34e15c1308418eb1 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 17:36:50 +0200 Subject: [PATCH 008/144] - Commented out printing within sd read and write to fasten things a bit up during testin --- bolthur/server/platform/raspi/storage/sd/rpc/read.c | 4 ++-- bolthur/server/platform/raspi/storage/sd/rpc/write.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bolthur/server/platform/raspi/storage/sd/rpc/read.c b/bolthur/server/platform/raspi/storage/sd/rpc/read.c index c1a13db9..85c11bee 100644 --- a/bolthur/server/platform/raspi/storage/sd/rpc/read.c +++ b/bolthur/server/platform/raspi/storage/sd/rpc/read.c @@ -84,12 +84,12 @@ void rpc_handle_read( return; } // calculate block number - const off_t block_number = request->offset / sd_block_size; + /*const off_t block_number = request->offset / sd_block_size; // try to read from card STARTUP_PRINT( "Reading %#zx bytes with offset of %llx / %lx ( block number: %llx ) from sd card\r\n", request->len, request->offset, ( uint32_t )request->offset, block_number - ) + )*/ // try to read data if ( ! sd_read_block( NULL, diff --git a/bolthur/server/platform/raspi/storage/sd/rpc/write.c b/bolthur/server/platform/raspi/storage/sd/rpc/write.c index 965c6cad..cac6841a 100644 --- a/bolthur/server/platform/raspi/storage/sd/rpc/write.c +++ b/bolthur/server/platform/raspi/storage/sd/rpc/write.c @@ -84,12 +84,12 @@ void rpc_handle_write( return; } // calculate block number - const off_t block_number = request->offset / sd_block_size; + /*const off_t block_number = request->offset / sd_block_size; // try to read from card STARTUP_PRINT( "Writing %#zx bytes with offset of %llx / %lx ( block number: %llx ) to sd card\r\n", request->len, request->offset, ( uint32_t )request->offset, block_number - ) + )*/ // try to read data if ( ! sd_write_block( NULL, From f2b2da1156188b676b93a6e8a9db23c6c1b3aef9 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 17:57:00 +0200 Subject: [PATCH 009/144] - Added device path constant for usbd - Added populate of device path, yet without any rpc bound to it --- bolthur/server/libusb.h | 2 ++ bolthur/server/usb/usbd/main.c | 20 +++++++++++++++++--- bolthur/server/usb/usbd/usbd.c | 5 ++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 2d5f5cd4..6ecc2a45 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -20,6 +20,8 @@ #ifndef _LIBUSB_H #define _LIBUSB_H +#define USBD_DEVICE_PATH "/dev/usb/usbd" + #define MAX_CHILDREN_PER_DEVICE 10 #define MAX_INTERFACES_PER_DEVICE 8 #define MAX_ENDPOINTS_PER_DEVICE 16 diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index 1c5e333c..b33360cb 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -22,6 +22,7 @@ #include #include "usbd.h" #include "rpc.h" +#include "../../libhelper.h" /** * @fn int main(int, char*[]) @@ -47,9 +48,22 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } - while ( true ) { - __asm__ __volatile__( "nop" ); + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); + + // add device file + /// FIXME: PREPARE RPC AND FILL THEN DEVICE INFO + STARTUP_PRINT( "Sending device to vfs\r\n" ) + /*uint32_t device_info[] = { HCD_SUBMIT_CONTROL_MESSAGE, }; + STARTUP_PRINT( "HCD_SUBMIT_CONTROL_MESSAGE = %d\r\n", HCD_SUBMIT_CONTROL_MESSAGE )*/ + if ( !dev_add_file( USBD_DEVICE_PATH, NULL, 0 ) ) { + STARTUP_PRINT( "Unable to add dev usbd\r\n" ) + return -1; } - return -1; + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index b9f460b6..d5079f21 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -1105,7 +1105,10 @@ int usbd_attach_device( libusb_device_t* dev ) { if ( buffer ) { free( buffer ); } - /// FIXME: ENUMERATE ALL DEVICES + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "dev->interfaces[ 0 ].class = %d\r\n", dev->interfaces[ 0 ].class ) + #endif // return success return 0; } From 62aa7978c6c2776ef3237762551ce10e5796203f Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 18:40:03 +0200 Subject: [PATCH 010/144] - Removed some comments after endif to keep code the same - Added some newlines where it was missing in STARTUP_PRINT - Started working on hub driver while working on usbd necessary for enumeration --- bolthur/kernel/platform/raspi/boot.h | 2 +- .../server/platform/raspi/storage/sd/main.c | 2 +- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 2 +- bolthur/server/platform/raspi/usb/hcd/main.c | 2 +- .../server/platform/raspi/usb/hcd/response.h | 2 +- bolthur/server/platform/raspi/usb/hcd/util.h | 2 +- bolthur/server/usb/device/hub/Makefile.am | 2 ++ bolthur/server/usb/device/hub/hub.c | 25 +++++++++++++++ bolthur/server/usb/device/hub/hub.h | 27 ++++++++++++++++ bolthur/server/usb/device/hub/main.c | 23 +++++++++++-- bolthur/server/usb/device/hub/rpc.h | 28 ++++++++++++++++ bolthur/server/usb/device/hub/rpc/init.c | 32 +++++++++++++++++++ bolthur/server/usb/usbd/main.c | 4 +-- 13 files changed, 143 insertions(+), 10 deletions(-) create mode 100644 bolthur/server/usb/device/hub/hub.c create mode 100644 bolthur/server/usb/device/hub/hub.h create mode 100644 bolthur/server/usb/device/hub/rpc.h create mode 100644 bolthur/server/usb/device/hub/rpc/init.c diff --git a/bolthur/kernel/platform/raspi/boot.h b/bolthur/kernel/platform/raspi/boot.h index 2f34a689..49fef64e 100644 --- a/bolthur/kernel/platform/raspi/boot.h +++ b/bolthur/kernel/platform/raspi/boot.h @@ -23,4 +23,4 @@ void boot_serial_init( void ); void boot_serial_putc(); -#endif //_PLATFORM_RASPI_BOOT_H +#endif diff --git a/bolthur/server/platform/raspi/storage/sd/main.c b/bolthur/server/platform/raspi/storage/sd/main.c index 868a8a57..8771aa90 100644 --- a/bolthur/server/platform/raspi/storage/sd/main.c +++ b/bolthur/server/platform/raspi/storage/sd/main.c @@ -70,7 +70,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // register rpc STARTUP_PRINT( "Setup rpc handler\r\n" ) if ( !rpc_init() ) { - STARTUP_PRINT( "Unable to bind rpc handler" ); + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); free( mbr_data ); return -1; } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 06f6eebc..587f4743 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -47,4 +47,4 @@ response_t dwhci_init_host( void ); response_t dwhci_enable_root_port( void ); response_t dwhci_init( void ); -#endif //_DWHCI_H +#endif diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index a0468c6f..22eb8e2c 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -40,7 +40,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // register rpc STARTUP_PRINT( "Setup rpc handler\r\n" ) if ( !rpc_init() ) { - STARTUP_PRINT( "Unable to bind rpc handler" ); + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); return -1; } diff --git a/bolthur/server/platform/raspi/usb/hcd/response.h b/bolthur/server/platform/raspi/usb/hcd/response.h index d889249a..3a899896 100644 --- a/bolthur/server/platform/raspi/usb/hcd/response.h +++ b/bolthur/server/platform/raspi/usb/hcd/response.h @@ -38,4 +38,4 @@ typedef struct { const char* response_error( response_t ); -#endif //_RESPONSE_H +#endif diff --git a/bolthur/server/platform/raspi/usb/hcd/util.h b/bolthur/server/platform/raspi/usb/hcd/util.h index c6d867a8..14aea02e 100644 --- a/bolthur/server/platform/raspi/usb/hcd/util.h +++ b/bolthur/server/platform/raspi/usb/hcd/util.h @@ -25,4 +25,4 @@ void* util_prepare_mmio_sequence( size_t, size_t* ); void* util_prepare_mailbox( size_t, size_t* ); -#endif //_UTIL_H +#endif diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index 21c0c17a..0e47f41f 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -3,5 +3,7 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hub\" bin_PROGRAMS = hub hub_SOURCES = \ + rpc/init.c \ + hub.c \ main.c hub_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/hub.c new file mode 100644 index 00000000..c9c679cb --- /dev/null +++ b/bolthur/server/usb/device/hub/hub.c @@ -0,0 +1,25 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "hub.h" + +int hub_init( void ) { + return ENOSYS; +} diff --git a/bolthur/server/usb/device/hub/hub.h b/bolthur/server/usb/device/hub/hub.h new file mode 100644 index 00000000..72d214ef --- /dev/null +++ b/bolthur/server/usb/device/hub/hub.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _HUB_H +#define _HUB_H + +#define HUB_ENABLE_DEBUG 1 + +int hub_init( void ); + +#endif diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index bff12006..74552057 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -20,6 +20,9 @@ #include #include +#include "hub.h" +#include "rpc.h" + /** * @fn int main(int, char*[]) * @brief main entry point @@ -29,7 +32,23 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print something - STARTUP_PRINT( "usb hub processing!\r\n" ) + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); + return -1; + } + + // setup hub interface + STARTUP_PRINT( "Setup hub interface!\r\n" ) + const int result = hub_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable initialize hub\r\n" ); + return -1; + } + + while ( true ) { + __asm__ __volatile__ ( "nop" ); + } return -1; } diff --git a/bolthur/server/usb/device/hub/rpc.h b/bolthur/server/usb/device/hub/rpc.h new file mode 100644 index 00000000..561839c5 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc.h @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +bool rpc_init( void ); + +#endif diff --git a/bolthur/server/usb/device/hub/rpc/init.c b/bolthur/server/usb/device/hub/rpc/init.c new file mode 100644 index 00000000..36eab1e5 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/init.c @@ -0,0 +1,32 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +// local includes +#include "../rpc.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + return true; +} diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index b33360cb..cdbb40ec 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -36,11 +36,11 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // register rpc STARTUP_PRINT( "Setup rpc handler\r\n" ) if ( !rpc_init() ) { - STARTUP_PRINT( "Unable to bind rpc handler" ); + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); return -1; } - // setup hcd interface + // setup usbd interface STARTUP_PRINT( "Setup usbd interface!\r\n" ) const int result = usbd_init(); if ( 0 != result ) { From f1420e6dd85beac57868f6dda7fd16ddbb030184 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 22 Jul 2025 19:41:18 +0200 Subject: [PATCH 011/144] - Extended libusb_device_t by pids for specific handlers - Added rpc structures for register and unregister device handler - Added rpc handler for register and unregister device handler --- bolthur/server/libusb.h | 46 ++++- .../usb/hcd/rpc/submit_control_message.c | 2 +- bolthur/server/usb/device/hub/hub.c | 4 + bolthur/server/usb/device/hub/main.c | 3 +- bolthur/server/usb/usbd/Makefile.am | 2 + bolthur/server/usb/usbd/main.c | 7 +- bolthur/server/usb/usbd/rpc.h | 2 + .../server/usb/usbd/rpc/handler/register.c | 157 ++++++++++++++++++ .../server/usb/usbd/rpc/handler/unregister.c | 157 ++++++++++++++++++ bolthur/server/usb/usbd/rpc/init.c | 13 ++ bolthur/server/usb/usbd/usbd.c | 11 +- bolthur/server/usb/usbd/usbd.h | 3 + 12 files changed, 396 insertions(+), 11 deletions(-) create mode 100644 bolthur/server/usb/usbd/rpc/handler/register.c create mode 100644 bolthur/server/usb/usbd/rpc/handler/unregister.c diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 6ecc2a45..6a599675 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -20,8 +20,38 @@ #ifndef _LIBUSB_H #define _LIBUSB_H +#include +#include + #define USBD_DEVICE_PATH "/dev/usb/usbd" +#define USBD_REGISTER_DEVICE_HANDLER RPC_CUSTOM_START +#define USBD_UNREGISTER_DEVICE_HANDLER USBD_REGISTER_DEVICE_HANDLER + 1 + +// external rpc declarations + +typedef enum { + DEVICE_HANDLER_TYPE_DETACHED = 1, + DEVICE_HANDLER_TYPE_DEALLOCATE = 2, + DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE = 3, + DEVICE_HANDLER_TYPE_CHILD_DETACHED = 4, + DEVICE_HANDLER_TYPE_CHILD_RESET = 5, + DEVICE_HANDLER_TYPE_CHECK_CONNECTION = 6, +} device_handler_type_t; + +typedef struct { + uint32_t device_number; + device_handler_type_t type; + pid_t handler; +} usbd_register_device_handler_t; + +typedef struct { + uint32_t device_number; + device_handler_type_t type; +} usbd_unregister_device_handler_t; + +// internal usb declarations + #define MAX_CHILDREN_PER_DEVICE 10 #define MAX_INTERFACES_PER_DEVICE 8 #define MAX_ENDPOINTS_PER_DEVICE 16 @@ -32,8 +62,6 @@ #pragma GCC diagnostic ignored "-Wpacked" #pragma GCC diagnostic ignored "-Wattributes" -#include - typedef enum { LIBUSB_DESCRIPTOR_DEVICE = 1, LIBUSB_DESCRIPTOR_CONFIGURATION = 2, @@ -364,6 +392,16 @@ typedef struct libusb_device { uint8_t port_number; libusb_transfer_error_t error __aligned( 4 ); + // processes responsible for generic detach and deallocate + pid_t device_detached_handler; + pid_t device_deallocate_handler; + // processes responsible for hub actions check for change, child detached + // child reset and check connection + pid_t device_check_for_change_handler; + pid_t device_child_detached_handler; + pid_t device_child_reset_handler; + pid_t device_check_connection_handler; + /** Handler for detaching the device. The device driver should not issue further requests to the device. */ void ( *device_detached )( libusb_device_t* device ) __aligned( 4 ); /** Handler for deallocation of the device. All memory in use by the device driver should be deallocated. */ @@ -372,9 +410,9 @@ typedef struct libusb_device { void ( *device_check_for_change )( libusb_device_t* device ); /** Handler for removing a child device from this device. Only hubs need handle with this. */ void ( *device_child_detached )( libusb_device_t* device, libusb_device_t* child ); - /** Handler for reseting a child device of this device. Only hubs need handle with this. */ + /** Handler for resetting a child device of this device. Only hubs need handle with this. */ int ( *device_child_reset )( libusb_device_t* device, libusb_device_t* child ); - /** Handler for reseting a child device of this device. Only hubs need handle with this. */ + /** Handler for resetting a child device of this device. Only hubs need handle with this. */ int ( *device_check_connection )( libusb_device_t* device, libusb_device_t* child ); libusb_device_descriptor_t descriptor __aligned( 4 ); diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c index 605eab0c..55e4c6e5 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -38,7 +38,7 @@ void rpc_submit_control_message( pid_t origin, size_t data_info, [[maybe_unused]] size_t response_info - ) { +) { vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/hub.c index c9c679cb..a3f584b7 100644 --- a/bolthur/server/usb/device/hub/hub.c +++ b/bolthur/server/usb/device/hub/hub.c @@ -17,8 +17,12 @@ * along with bolthur/kernel. If not, see . */ +// system includes #include +// local includes #include "hub.h" +// driver includes +#include "../../../libusb.h" int hub_init( void ) { return ENOSYS; diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 74552057..7030d1c3 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -17,9 +17,10 @@ * along with bolthur/kernel. If not, see . */ +// system includes #include #include - +// local includes #include "hub.h" #include "rpc.h" diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index 2977c1e4..ae7aaf68 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -3,6 +3,8 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/usbd\" bin_PROGRAMS = usbd usbd_SOURCES = \ + rpc/handler/register.c \ + rpc/handler/unregister.c \ rpc/init.c \ main.c \ usbd.c diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index cdbb40ec..6e90c137 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -55,9 +55,10 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // add device file /// FIXME: PREPARE RPC AND FILL THEN DEVICE INFO STARTUP_PRINT( "Sending device to vfs\r\n" ) - /*uint32_t device_info[] = { HCD_SUBMIT_CONTROL_MESSAGE, }; - STARTUP_PRINT( "HCD_SUBMIT_CONTROL_MESSAGE = %d\r\n", HCD_SUBMIT_CONTROL_MESSAGE )*/ - if ( !dev_add_file( USBD_DEVICE_PATH, NULL, 0 ) ) { + uint32_t device_info[] = { + USBD_REGISTER_DEVICE_HANDLER, + USBD_UNREGISTER_DEVICE_HANDLER, }; + if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 2 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/usbd/rpc.h b/bolthur/server/usb/usbd/rpc.h index 561839c5..e0438074 100644 --- a/bolthur/server/usb/usbd/rpc.h +++ b/bolthur/server/usb/usbd/rpc.h @@ -24,5 +24,7 @@ #include bool rpc_init( void ); +void rpc_handler_register( size_t, pid_t, size_t, size_t ); +void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); #endif diff --git a/bolthur/server/usb/usbd/rpc/handler/register.c b/bolthur/server/usb/usbd/rpc/handler/register.c new file mode 100644 index 00000000..27b23b61 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/handler/register.c @@ -0,0 +1,157 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler for device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_handler_register( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + const usbd_register_device_handler_t* message = ( usbd_register_device_handler_t* )request->container; + // validate against handler enum + if ( + message->type < DEVICE_HANDLER_TYPE_DETACHED + || message->type > DEVICE_HANDLER_TYPE_CHECK_CONNECTION + ) { + error.status = -EIO; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // try to find hub + libusb_device_t* current = head; + while ( current ) { + // handle matching number + if ( current->number == message->device_number ) { + break; + } + // go to next + current = current->next; + } + // handle not found + if ( ! current ) { + free( request ); + error.status = -ENXIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // assert not set + bool handler_not_yet_set = true; + switch ( message->type ) { + case DEVICE_HANDLER_TYPE_DETACHED: + handler_not_yet_set = -1 == current->device_detached_handler; + break; + case DEVICE_HANDLER_TYPE_DEALLOCATE: + handler_not_yet_set = -1 == current->device_deallocate_handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: + handler_not_yet_set = -1 == current->device_check_for_change_handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_DETACHED: + handler_not_yet_set = -1 == current->device_child_detached_handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_RESET: + handler_not_yet_set = -1 == current->device_child_reset_handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: + handler_not_yet_set = -1 == current->device_check_connection_handler; + break; + } + // handle already set + if ( ! handler_not_yet_set ) { + free( request ); + error.status = -EADDRINUSE; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate response message + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + sizeof( bool ); + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + memset( response, 0, response_size ); + // just set it to the handler + switch ( message->type ) { + case DEVICE_HANDLER_TYPE_DETACHED: + handler_not_yet_set = message->handler; + break; + case DEVICE_HANDLER_TYPE_DEALLOCATE: + handler_not_yet_set = message->handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: + handler_not_yet_set = message->handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_DETACHED: + handler_not_yet_set = message->handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_RESET: + handler_not_yet_set = message->handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: + handler_not_yet_set = message->handler; + break; + } + // return success + response->status = 0; + *( bool* )response->container = true; + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/handler/unregister.c b/bolthur/server/usb/usbd/rpc/handler/unregister.c new file mode 100644 index 00000000..949ff43c --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/handler/unregister.c @@ -0,0 +1,157 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler for device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_handler_unregister( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + const usbd_unregister_device_handler_t* message = ( usbd_unregister_device_handler_t* )request->container; + // validate against handler enum + if ( + message->type < DEVICE_HANDLER_TYPE_DETACHED + || message->type > DEVICE_HANDLER_TYPE_CHECK_CONNECTION + ) { + error.status = -EIO; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // try to find hub + libusb_device_t* current = head; + while ( current ) { + // handle matching number + if ( current->number == message->device_number ) { + break; + } + // go to next + current = current->next; + } + // handle not found + if ( ! current ) { + free( request ); + error.status = -ENXIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // assert not set + bool handler_not_yet_set = true; + switch ( message->type ) { + case DEVICE_HANDLER_TYPE_DETACHED: + handler_not_yet_set = -1 == current->device_detached_handler; + break; + case DEVICE_HANDLER_TYPE_DEALLOCATE: + handler_not_yet_set = -1 == current->device_deallocate_handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: + handler_not_yet_set = -1 == current->device_check_for_change_handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_DETACHED: + handler_not_yet_set = -1 == current->device_child_detached_handler; + break; + case DEVICE_HANDLER_TYPE_CHILD_RESET: + handler_not_yet_set = -1 == current->device_child_reset_handler; + break; + case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: + handler_not_yet_set = -1 == current->device_check_connection_handler; + break; + } + // handle already set + if ( handler_not_yet_set ) { + free( request ); + error.status = -EINVAL; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate response message + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + sizeof( bool ); + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + memset( response, 0, response_size ); + // just set it to the handler + switch ( message->type ) { + case DEVICE_HANDLER_TYPE_DETACHED: + handler_not_yet_set = -1; + break; + case DEVICE_HANDLER_TYPE_DEALLOCATE: + handler_not_yet_set = -1; + break; + case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: + handler_not_yet_set = -1; + break; + case DEVICE_HANDLER_TYPE_CHILD_DETACHED: + handler_not_yet_set = -1; + break; + case DEVICE_HANDLER_TYPE_CHILD_RESET: + handler_not_yet_set = -1; + break; + case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: + handler_not_yet_set = -1; + break; + } + // return success + response->status = 0; + *( bool* )response->container = true; + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c index 36eab1e5..8abe2c0c 100644 --- a/bolthur/server/usb/usbd/rpc/init.c +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -21,6 +21,7 @@ #include // local includes #include "../rpc.h" +#include "../../../libusb.h" /** * @fn bool rpc_init(void) @@ -28,5 +29,17 @@ * @return */ bool rpc_init( void ) { + // register handler register + bolthur_rpc_bind( USBD_REGISTER_DEVICE_HANDLER, rpc_handler_register, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register handler register device handler!\r\n" ) + return false; + } + // register handler unregister + bolthur_rpc_bind( USBD_UNREGISTER_DEVICE_HANDLER, rpc_handler_unregister, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register handler unregister device handler!\r\n" ) + return false; + } return true; } diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index d5079f21..f41f12ce 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -33,12 +33,12 @@ /** * @brief Static file descriptor for hcd operations */ -static int fd_hcd = -1; +int fd_hcd = -1; /** * @brief Head of device list */ -static libusb_device_t* head = nullptr; +libusb_device_t* head = nullptr; /** * @brief Default timeout for control messages @@ -180,6 +180,13 @@ int usbd_allocate_device( libusb_device_t** dev, bool insert_head ) { ( *dev )->device_check_for_change = nullptr; ( *dev )->device_child_detached = nullptr; ( *dev )->device_child_reset = nullptr; + // setup handlers with invalid pid + ( *dev )->device_detached_handler = -1; + ( *dev )->device_deallocate_handler = -1; + ( *dev )->device_check_for_change_handler = -1; + ( *dev )->device_child_detached_handler = -1; + ( *dev )->device_child_reset_handler = -1; + ( *dev )->device_check_connection_handler = -1; // return success return 0; } diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h index 8c68d5cb..714a846e 100644 --- a/bolthur/server/usb/usbd/usbd.h +++ b/bolthur/server/usb/usbd/usbd.h @@ -24,6 +24,9 @@ #define USBD_ENABLE_DEBUG 1 +extern int fd_hcd; +extern libusb_device_t* head; + void usbd_deallocate_device( libusb_device_t* ); int usbd_allocate_device( libusb_device_t**, bool ); int usbd_control_message( libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t ); From c2468dde66722fe86a53fcbb24ac6e5a7e3b4c67 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Wed, 23 Jul 2025 22:40:13 +0200 Subject: [PATCH 012/144] - Moved usbd types below the usb defines - Added new libusb library to abstract communication with usbd a bit - Added two new rpcs, one for performing control message and one to get description - Added init of usb library to hub driver - Started implementing usb hub init --- bolthur/library/Makefile.am | 2 +- bolthur/library/configure.ac | 1 + bolthur/library/usb/Makefile.am | 6 + bolthur/library/usb/usb.c | 512 +++++++++++ bolthur/library/usb/usb.h | 34 + bolthur/server/libusb.h | 107 ++- bolthur/server/platform/raspi/usb/hcd/dwhci.c | 39 +- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 13 + .../platform/raspi/usb/hcd/dwhciroothub.c | 35 +- .../usb/hcd/rpc/submit_control_message.c | 25 +- bolthur/server/usb/device/hub/Makefile.am | 4 + bolthur/server/usb/device/hub/hub.c | 808 +++++++++++++++++- bolthur/server/usb/device/hub/hub.h | 10 + bolthur/server/usb/device/hub/main.c | 10 + bolthur/server/usb/usbd/Makefile.am | 5 + bolthur/server/usb/usbd/main.c | 11 +- bolthur/server/usb/usbd/rpc.h | 5 + bolthur/server/usb/usbd/rpc/attach/device.c | 123 +++ bolthur/server/usb/usbd/rpc/control/message.c | 114 +++ bolthur/server/usb/usbd/rpc/get/description.c | 106 +++ bolthur/server/usb/usbd/rpc/get/descriptor.c | 116 +++ bolthur/server/usb/usbd/rpc/get/roothub.c | 120 +++ .../server/usb/usbd/rpc/handler/register.c | 2 + .../server/usb/usbd/rpc/handler/unregister.c | 2 + bolthur/server/usb/usbd/rpc/init.c | 34 +- bolthur/server/usb/usbd/usbd.c | 13 + bolthur/server/usb/usbd/usbd.h | 1 + 27 files changed, 2183 insertions(+), 75 deletions(-) create mode 100644 bolthur/library/usb/Makefile.am create mode 100644 bolthur/library/usb/usb.c create mode 100644 bolthur/library/usb/usb.h create mode 100644 bolthur/server/usb/usbd/rpc/attach/device.c create mode 100644 bolthur/server/usb/usbd/rpc/control/message.c create mode 100644 bolthur/server/usb/usbd/rpc/get/description.c create mode 100644 bolthur/server/usb/usbd/rpc/get/descriptor.c create mode 100644 bolthur/server/usb/usbd/rpc/get/roothub.c diff --git a/bolthur/library/Makefile.am b/bolthur/library/Makefile.am index 1b1f4faf..eaa5465c 100644 --- a/bolthur/library/Makefile.am +++ b/bolthur/library/Makefile.am @@ -1,4 +1,4 @@ ACLOCAL_AMFLAGS = -I ../../build-aux/m4 -SUBDIRS = collection framebuffer handle +SUBDIRS = collection framebuffer handle usb diff --git a/bolthur/library/configure.ac b/bolthur/library/configure.ac index df73e08f..e1e04f11 100644 --- a/bolthur/library/configure.ac +++ b/bolthur/library/configure.ac @@ -139,6 +139,7 @@ AC_CONFIG_FILES([ collection/list/Makefile framebuffer/Makefile handle/Makefile + usb/Makefile ]) # FIXME: REPLACE WITH SUBMODULE WHEN MOVING TO OWN REPO diff --git a/bolthur/library/usb/Makefile.am b/bolthur/library/usb/Makefile.am new file mode 100644 index 00000000..4f49e39a --- /dev/null +++ b/bolthur/library/usb/Makefile.am @@ -0,0 +1,6 @@ + +AM_CFLAGS = -DPROGRAM_NAME=\"bolthur/libusb\" + +noinst_LTLIBRARIES = libusb.la +libusb_la_SOURCES = \ + usb.c diff --git a/bolthur/library/usb/usb.c b/bolthur/library/usb/usb.c new file mode 100644 index 00000000..65ae67c0 --- /dev/null +++ b/bolthur/library/usb/usb.c @@ -0,0 +1,512 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +#include +// local includes +#include "usb.h" +// server includes +#include "../../server/libusb.h" + +static int fd_usbd = -1; + +/** + * @fn int usb_init( void ) + * @brief USB library init + * @return + */ +int usb_init( void ) { + // handle already initialized + if ( fd_usbd != -1 ) { + return 0; + } + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Opening %s\r\n", USBD_DEVICE_PATH ) + #endif + // open handle + fd_usbd = open( USBD_DEVICE_PATH, O_RDWR ); + // handle error + if ( fd_usbd == -1 ) { + return errno; + } + // return success + return 0; +} + +/** + * @fn const char* usb_get_description(const libusb_device_t*) + * @brief Wrapper to get description for device + * @param dev + * @return + */ +const char* usb_get_description( const libusb_device_t* dev ) { + // local buffer for description + static char buffer[ 256 ]; + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Fetching usb description\r\n" ) + #endif + // clear out buffer + memset( buffer, 0, sizeof( buffer ) ); + // allocate device + usbd_get_description_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return buffer; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->status = dev->status; + request->usb_version = dev->descriptor.usb_version; + request->product_id = dev->descriptor.product_id; + request->vendor_id = dev->descriptor.vendor_id; + request->protocol = dev->interfaces[ 0 ].protocol; + request->class = dev->interfaces[ 0 ].class; + // perform ioctl command + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_DESCRIPTION, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + // return eio + return buffer; + } + // copy over response + strcpy( buffer, ( const char* )request ); + // free request + free( request ); + // return copied buffer + return buffer; +} + +/** + * @fn int usb_control_message(libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t) + * @brief Wrapper to perform usb control message + * @param dev + * @param pipe + * @param buffer + * @param buffer_length + * @param request + * @param timeout + * @return + */ +int usb_control_message( + libusb_device_t* dev, + const libusb_pipe_address_t pipe, + void* buffer, + const size_t buffer_length, + const libusb_device_request_t* request, + const size_t timeout +) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "firing usb control message\r\n" ) + #endif + // allocate shared memory + const size_t data_size = sizeof ( usb_control_message_t ) + buffer_length + 1; + const size_t shm_id = _syscall_memory_shared_create( data_size ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + return e; + } + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + return e; + } + usb_control_message_t* message = ( usb_control_message_t* )shm_addr; + // populate real message in shared memory + memcpy( &message->device, dev, sizeof( libusb_device_t ) ); + memcpy( &message->pipe_address, &pipe, sizeof( pipe ) ); + memcpy( &message->request, request, sizeof( *request ) ); + message->buffer_length = buffer_length; + message->timeout = timeout; + if ( LIBUSB_DIRECTION_OUT == pipe.direction && buffer ) { + memcpy( &message->buffer, buffer, buffer_length ); + } + // allocate request + usbd_control_message_t* control_request = malloc( sizeof( *control_request ) ); + if ( ! control_request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return error + return ENOMEM; + } + // clear out everything + memset( control_request, 0, sizeof( *control_request ) ); + // populate shm_id + control_request->shm_id = shm_id; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_CONTROL_MESSAGE, + sizeof( *control_request ), + IOCTL_RDWR + ), + control_request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( control_request ); + // return eio + return EIO; + } + // response is equal to input + if ( message->device.error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Message to %s timeout reached\r\n", usb_get_description( dev ) ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control_request + free( control_request ); + // return timeout + return ETIMEDOUT; + } + // copy over data + if ( LIBUSB_DIRECTION_IN == pipe.direction && buffer ) { + memcpy( buffer, message->buffer, buffer_length ); + } + // copy over static fields into device populated via shared memory + dev->error = message->device.error; + dev->last_transfer = message->device.last_transfer; + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control message + free( control_request ); + // return result + return result; +} + +/** + * @fn libusb_device_t* usb_get_root_hub(void) + * @brief Wrapper to get root hub + * @return + */ +libusb_device_t* usb_get_root_hub( void ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "firing usb get root hub\r\n" ) + #endif + // allocate shared memory + const size_t shm_id = _syscall_memory_shared_create( sizeof( libusb_device_t ) ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + errno = e; + return nullptr; + } + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + errno = e; + return nullptr; + } + // clear out + memset( shm_addr, 0, sizeof( libusb_device_t ) ); + // allocate request + usbd_get_roothub_t* request = malloc( sizeof( *request ) ); + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return error + errno = ENOMEM; + return nullptr; + } + // clear out everything + memset( request, 0, sizeof( *request ) ); + // populate shm_id + request->shm_id = shm_id; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_ROOTHUB, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( request ); + // return eio + errno = EIO; + return nullptr; + } + // allocate device locally + libusb_device_t* dev = malloc( sizeof( *dev ) ); + // handle error + if ( ! dev ) { + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate space for return\r\n" ) + #endif + errno = ENOMEM; + return nullptr; + } + // copy over + memcpy( dev, shm_addr, sizeof( *dev ) ); + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( request ); + // return device + return dev; +} + +/** + * @fn int usb_get_descriptor(libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t) + * @brief Wrapper to get usb descriptor + * @param dev + * @param type + * @param index + * @param lang_id + * @param buffer + * @param buffer_length + * @param minimum_length + * @param recipient + * @return + */ +int usb_get_descriptor( + const libusb_device_t* dev, + const libusb_descriptor_type_t type, + const uint8_t index, + const uint16_t lang_id, + void* buffer, + const size_t buffer_length, + const size_t minimum_length, + const uint8_t recipient +) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "firing usb get descriptor\r\n" ) + #endif + // allocate shared memory + const size_t data_size = sizeof ( usb_descriptor_message_t ) + buffer_length + 1; + const size_t shm_id = _syscall_memory_shared_create( data_size ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + return e; + } + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + return e; + } + usb_descriptor_message_t* message = ( usb_descriptor_message_t* )shm_addr; + // populate real message in shared memory + memcpy( &message->device, dev, sizeof( libusb_device_t ) ); + message->type = type; + message->index = index; + message->lang_id = lang_id; + message->buffer_length = buffer_length; + message->minimum_length = minimum_length; + message->recipient = recipient; + if ( buffer ) { + memcpy( &message->buffer, buffer, buffer_length ); + } + // allocate request + usbd_get_descriptor_t* control_request = malloc( sizeof( *control_request ) ); + if ( ! control_request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return error + return ENOMEM; + } + // clear out everything + memset( control_request, 0, sizeof( *control_request ) ); + // populate shm_id + control_request->shm_id = shm_id; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_DESCRIPTOR, + sizeof( *control_request ), + IOCTL_RDWR + ), + control_request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( control_request ); + // return eio + return EIO; + } + // copy over data + if ( buffer ) { + memcpy( buffer, message->buffer, buffer_length ); + } + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control message + free( control_request ); + // return result + return result; +} + +/** + * @fn int usb_attach_device(uint32_t, uint32_t) + * @brief Method to attach a new discovered device + * @param parent_number + * @param port_number + * @param speed + * @return + */ +int usb_attach_device( const uint32_t parent_number, const uint32_t port_number, libusb_speed_t speed ) { + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Attaching device %"PRIu32" to %"PRIu32"\r\n", + port_number, parent_number ) + #endif + // allocate device + usbd_attach_device_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->parent_number = parent_number; + request->port_number = port_number; + request->speed = speed; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_ATTACH_DEVICE, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + return 0; +} diff --git a/bolthur/library/usb/usb.h b/bolthur/library/usb/usb.h new file mode 100644 index 00000000..3ebf3181 --- /dev/null +++ b/bolthur/library/usb/usb.h @@ -0,0 +1,34 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _USB_H +#define _USB_H + +#include "../../server/libusb.h" + +#define LIBUSB_ENABLE_DEBUG 1 + +int usb_init( void ); +const char* usb_get_description( const libusb_device_t* ); +int usb_control_message( libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t ); +libusb_device_t* usb_get_root_hub( void ); +int usb_get_descriptor( const libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t ); +int usb_attach_device( uint32_t, uint32_t, libusb_speed_t ); + +#endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 6a599675..d0874fd7 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -23,33 +23,6 @@ #include #include -#define USBD_DEVICE_PATH "/dev/usb/usbd" - -#define USBD_REGISTER_DEVICE_HANDLER RPC_CUSTOM_START -#define USBD_UNREGISTER_DEVICE_HANDLER USBD_REGISTER_DEVICE_HANDLER + 1 - -// external rpc declarations - -typedef enum { - DEVICE_HANDLER_TYPE_DETACHED = 1, - DEVICE_HANDLER_TYPE_DEALLOCATE = 2, - DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE = 3, - DEVICE_HANDLER_TYPE_CHILD_DETACHED = 4, - DEVICE_HANDLER_TYPE_CHILD_RESET = 5, - DEVICE_HANDLER_TYPE_CHECK_CONNECTION = 6, -} device_handler_type_t; - -typedef struct { - uint32_t device_number; - device_handler_type_t type; - pid_t handler; -} usbd_register_device_handler_t; - -typedef struct { - uint32_t device_number; - device_handler_type_t type; -} usbd_unregister_device_handler_t; - // internal usb declarations #define MAX_CHILDREN_PER_DEVICE 10 @@ -532,4 +505,84 @@ typedef enum { // enable warnings again #pragma GCC diagnostic pop +#define USBD_DEVICE_PATH "/dev/usb/usbd" + +#define USBD_REGISTER_DEVICE_HANDLER RPC_CUSTOM_START +#define USBD_UNREGISTER_DEVICE_HANDLER USBD_REGISTER_DEVICE_HANDLER + 1 +#define USBD_CONTROL_MESSAGE USBD_UNREGISTER_DEVICE_HANDLER + 1 +#define USBD_GET_DESCRIPTION USBD_CONTROL_MESSAGE + 1 +#define USBD_GET_ROOTHUB USBD_GET_DESCRIPTION + 1 +#define USBD_GET_DESCRIPTOR USBD_GET_ROOTHUB + 1 +#define USBD_ATTACH_DEVICE USBD_GET_DESCRIPTOR + 1 + +// external rpc declarations + +typedef enum { + DEVICE_HANDLER_TYPE_DETACHED = 1, + DEVICE_HANDLER_TYPE_DEALLOCATE = 2, + DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE = 3, + DEVICE_HANDLER_TYPE_CHILD_DETACHED = 4, + DEVICE_HANDLER_TYPE_CHILD_RESET = 5, + DEVICE_HANDLER_TYPE_CHECK_CONNECTION = 6, +} device_handler_type_t; + +typedef struct { + uint32_t device_number; + device_handler_type_t type; + pid_t handler; +} usbd_register_device_handler_t; + +typedef struct { + uint32_t device_number; + device_handler_type_t type; +} usbd_unregister_device_handler_t; + +typedef struct { + size_t shm_id; +} usbd_control_message_t; + +typedef struct { + libusb_device_status_t status; + uint16_t usb_version; + uint16_t vendor_id; + uint16_t product_id; + libusb_interface_class_t class; + uint8_t protocol; + char buffer[ 256 ]; +} usbd_get_description_t; + +typedef struct { + size_t shm_id; +} usbd_get_roothub_t; + +typedef struct { + size_t shm_id; +} usbd_get_descriptor_t; + +typedef struct { + uint32_t parent_number; + uint32_t port_number; + libusb_speed_t speed; +} usbd_attach_device_t; + +typedef struct { + libusb_device_t device; + libusb_pipe_address_t pipe_address; + libusb_device_request_t request; + size_t buffer_length; + size_t timeout; + uint8_t buffer[]; +} usb_control_message_t; + +typedef struct { + libusb_device_t device; + libusb_descriptor_type_t type; + uint8_t index; + uint16_t lang_id; + size_t buffer_length; + size_t minimum_length; + uint8_t recipient; + uint8_t buffer[]; +} usb_descriptor_message_t; + #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index 40f26e3b..952b326b 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -749,14 +749,20 @@ response_t dwhci_init_core( void ) { HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED ) { + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT("SET ULPI_FSLS AND CLK_SUS_M\r\n") + #endif + // enable configuration cfg |= - HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS - | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M; - } else { - cfg &= ( uint32_t )( - ~HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS - & ~HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M - ); + HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M; + } + else { + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT("UNSET ULPI_FSLS AND CLK_SUS_M\r\n") + #endif + // disable configuration + cfg &= (uint32_t)~( + HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M ); } // write back cfg @@ -858,8 +864,7 @@ response_t dwhci_init_core( void ) { // free sequence free( sequence ); // manipulate config - /// FIXME: ENABLE DMA AND WORK WITH INTERRUPTS - //ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; + ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES; ahb_cfg &= ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_MASK; // allocate sequence to write it back @@ -1036,10 +1041,10 @@ response_t dwhci_core_flush_tx_fifo( const uint32_t num_fifo ) { #endif // set initial reset fifo flush - const uint32_t reset = ( - HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH - & ( uint32_t )~HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_MASK - ) | ( num_fifo << HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT ); + uint32_t reset = 0; + reset |= HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH; + reset &= ( uint32_t )~HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_MASK; + reset |= num_fifo << HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT; // allocate sequence size_t sequence_size; @@ -1177,7 +1182,7 @@ response_t dwhci_core_flush_rx_fifo( void ) { * @param port * @return */ -response_t dwhci_write_host_port( uint32_t port ) { +response_t dwhci_write_host_port( const uint32_t port ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Writing host port value %#"PRIx32"\r\n", port ) @@ -1488,7 +1493,7 @@ response_t dwhci_init_host( void ) { if ( HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED - && HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS == core_cfg + && HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS & core_cfg ) { host_cfg |= HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ; } else { @@ -1524,7 +1529,7 @@ response_t dwhci_init_host( void ) { if ( -1 == ioctl_result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Phy power reset failed\r\n" ) + STARTUP_PRINT( "Set host config failed\r\n" ) #endif // free sequence free( sequence ); @@ -1751,7 +1756,7 @@ response_t dwhci_enable_root_port( void ) { // read host port uint32_t host_port; - response_t result = dwhci_read_host_port( &host_port ); + const response_t result = dwhci_read_host_port( &host_port ); // handle error if ( HCD_RESPONSE_OK != result ) { // debug output diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 587f4743..e91b5066 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -21,12 +21,25 @@ #define _DWHCI_H #include +#include "../../../../libusb.h" #include "response.h" #define DWHCI_ENABLE_DEBUG 1 extern int fd_iomem; +typedef enum { + DWHCI_CHANNEL_STATE_DATA0 = 0, + DWHCI_CHANNEL_STATE_DATA1 = 2, + DWHCI_CHANNEL_STATE_DATA2 = 1, + DWHCI_CHANNEL_STATE_MDATA = 3, + DWHCI_CHANNEL_STATE_SETUP = 3, +} dwhci_channel_state_t; + +response_t dwhci_prepare_channel( libusb_device_t*, uint8_t, uint32_t, dwhci_channel_state_t, libusb_pipe_address_t* ); +response_t dwhci_channel_send_wait_one( libusb_device_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, uint32_t, libusb_device_request_t* ); +response_t dwhci_channel_send_wait( libusb_device_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, libusb_device_request_t*, dwhci_channel_state_t ); + response_t dwhci_query_vendor( uint32_t* destination ); response_t dwhci_power_on( void ); response_t dwhci_enable_global_interrupts( void ); diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c index eaa26775..f3200447 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c @@ -208,6 +208,7 @@ int dwhciroothub_process( dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } + STARTUP_PRINT( "host_port = %"PRIx32"\r\n", host_port ) // push to local variable libusb_hub_port_full_status_t status = { .status = { @@ -236,6 +237,7 @@ int dwhciroothub_process( const uint32_t val = 0; memcpy( buffer, &val, sizeof( val ) ); memcpy( buffer, &status, sizeof( status ) ); + reply_length = 4; break; default: dev->error = LIBUSB_TRANSFER_ERROR_STALL; @@ -250,6 +252,7 @@ int dwhciroothub_process( case 0x23: switch ( ( libusb_hub_port_feature_t)request->value ) { case LIBUSB_HUB_PORT_FEATURE_ENABLE: + STARTUP_PRINT( "roothub port feature enable!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -259,13 +262,14 @@ int dwhciroothub_process( // set enable host_port |= HCD_DWHCI_HOST_PORT_ENABLE; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x4 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_SUSPEND: + STARTUP_PRINT( "roothub port feature suspend!\r\n" ) // allocate sequence sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { @@ -286,7 +290,7 @@ int dwhciroothub_process( sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_PORT; sequence[ 2 ].value = HCD_DWHCI_HOST_PORT_RESUME; // write host port with resume enabled - sequence[ 3 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 3 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_PORT; sequence[ 3 ].value = 0x40; // delay 200 milliseconds @@ -299,9 +303,9 @@ int dwhciroothub_process( sequence[ 5 ].value = ( uint32_t )~( HCD_DWHCI_HOST_PORT_RESUME | HCD_DWHCI_HOST_PORT_SUSPEND ); // write back with suspend false - sequence[ 6 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 6 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; sequence[ 6 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 6 ].value = ( uint32_t )0xc0; + sequence[ 6 ].value = 0xc0; // execute sequence ioctl_result = ioctl( fd_iomem, @@ -321,6 +325,7 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_POWER: + STARTUP_PRINT( "roothub port feature power!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -330,13 +335,14 @@ int dwhciroothub_process( // reset power bit host_port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_POWER; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x1000 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE: + STARTUP_PRINT( "roothub port feature connection change!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -346,13 +352,14 @@ int dwhciroothub_process( // set connect changed host_port |= HCD_DWHCI_HOST_PORT_CONNECT_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x2 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE: + STARTUP_PRINT( "roothub port feature enable change!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -362,13 +369,14 @@ int dwhciroothub_process( // set enable changed host_port |= HCD_DWHCI_HOST_PORT_ENABLE_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x8 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE: + STARTUP_PRINT( "roothub port feature over current change!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -378,7 +386,7 @@ int dwhciroothub_process( // set over current changed host_port |= HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x20 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; @@ -398,6 +406,7 @@ int dwhciroothub_process( case 0x23: switch ( ( libusb_hub_port_feature_t )request->value ) { case LIBUSB_HUB_PORT_FEATURE_RESET: + STARTUP_PRINT( "roothub port feature reset!\r\n" ) // allocate sequence sequence = util_prepare_mmio_sequence( 8, &sequence_size ); if ( ! sequence ) { @@ -422,8 +431,8 @@ int dwhciroothub_process( sequence[ 3 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_SUSPEND; // write back power with enabled reset and power flag and disabled suspend flag sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; - sequence[ 4 ].offset = PERIPHERAL_USB_POWER_OFFSET; - sequence[ 4 ].value = HCD_DWHCI_HOST_PORT_RESET | HCD_DWHCI_HOST_PORT_POWER; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 4 ].value = HCD_DWHCI_HOST_PORT_RESET | HCD_DWHCI_HOST_PORT_POWER | 0x1180; // delay 200 milliseconds sequence[ 5 ].type = IOMEM_MMIO_ACTION_SLEEP; sequence[ 5 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; @@ -433,8 +442,9 @@ int dwhciroothub_process( sequence[ 6 ].offset = PERIPHERAL_DWHCI_HOST_PORT; sequence[ 6 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_RESET; // write back previous read - sequence[ 7 ].type = IOMEM_MMIO_ACTION_WRITE_PREVIOUS_READ; + sequence[ 7 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; sequence[ 7 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 7 ].value = 0x1000; // execute sequence ioctl_result = ioctl( fd_iomem, @@ -454,6 +464,7 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_POWER: + STARTUP_PRINT( "roothub port feature power!\r\n" ) // read host port dwhci_result = dwhci_read_host_port( &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -463,7 +474,7 @@ int dwhciroothub_process( // set over current changed host_port |= HCD_DWHCI_HOST_PORT_POWER; // write back host port - dwhci_result = dwhci_write_host_port( host_port ); + dwhci_result = dwhci_write_host_port( host_port | 0x1000 ); if ( HCD_RESPONSE_OK != dwhci_result ) { dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c index 55e4c6e5..b8b3a71c 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -77,6 +77,17 @@ void rpc_submit_control_message( } // transform shared memory into message hcd_control_message_t* message = ( hcd_control_message_t* )shm_addr; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } // handle root hub device if ( dwhciroothub_root_hub_device_number == message->pipe_address.device ) { // try to process root hub @@ -95,34 +106,26 @@ void rpc_submit_control_message( _syscall_memory_shared_detach( submit_control_message->shm_id ); // free request free( request ); + free( response ); // return from rpc bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } } else { + STARTUP_PRINT( "PERFORM MESSAGE!\r\n" ) // set error error.status = -ENOSYS; // detach shared memory _syscall_memory_shared_detach( submit_control_message->shm_id ); // free request free( request ); + free( response ); // return from rpc bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } // detach shared memory _syscall_memory_shared_detach( submit_control_message->shm_id ); - // allocate response structure - const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; - vfs_ioctl_perform_response_t* response = malloc( response_size ); - if ( ! response ) { - error.status = -ENOMEM; - // free request - free( request ); - // return from rpc - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } // populate status and just copy over data from request response->status = 0; memcpy( response->container, request->container, container_size ); diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index 0e47f41f..351254e2 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -2,6 +2,10 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hub\" bin_PROGRAMS = hub +hub_DEPENDENCIES = \ + ${abs_top_builddir}/../library/usb/libusb.la +hub_LDADD = \ + ${abs_top_builddir}/../library/usb/libusb.la hub_SOURCES = \ rpc/init.c \ hub.c \ diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/hub.c index a3f584b7..cef827c0 100644 --- a/bolthur/server/usb/device/hub/hub.c +++ b/bolthur/server/usb/device/hub/hub.c @@ -19,11 +19,815 @@ // system includes #include +#include +#include +#include // local includes #include "hub.h" -// driver includes -#include "../../../libusb.h" +// library includes +#include "../../../../library/usb/usb.h" +// disable malloc warning since read descriptor is wanted to allocate stuff +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" + +/** + * @fn int hub_read_descriptor(libusb_device_t*) + * @brief Wrapper to read out hub descriptor in driver + * @param dev + * @return + */ +int hub_read_descriptor( const libusb_device_t* dev ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Reading usb hub descriptor\r\n" ) + #endif + // space for buffer on stack + libusb_descriptor_header_t header; + // get hub descriptor + int result = usb_get_descriptor( dev, LIBUSB_DESCRIPTOR_HUB, 0, 0, &header, + sizeof( header ), sizeof( header ), 0x20 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get hub descriptor header: %s\r\n", + strerror( result ) ); + #endif + // return result + return result; + } + // allocate space in driver data + if ( ! ( ( libusb_hub_device_t* )dev->driver_data )->descriptor ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Allocating memory for hub descriptor" ); + #endif + // allocate memory + ( ( libusb_hub_device_t* )dev->driver_data )->descriptor = malloc( header.descriptor_length ); + // handle error + if ( ! ( ( libusb_hub_device_t* )dev->driver_data )->descriptor ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate memory for hub descriptor" ); + #endif + // return nomem + return ENOMEM; + } + } + // read descriptor itself + result = usb_get_descriptor( dev, LIBUSB_DESCRIPTOR_HUB, 0, 0, + ( ( libusb_hub_device_t* )dev->driver_data )->descriptor, + header.descriptor_length, header.descriptor_length, 0x20 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get hub descriptor: %s\r\n", strerror( result ) ); + #endif + // return result + return result; + } + // return success + return 0; +} + +// enable warnings again +#pragma GCC diagnostic pop + +/** + * @fn int hub_get_status(libusb_device_t*) + * @brief Method to retrieve host status + * @param dev + * @return + */ +int hub_get_status( libusb_device_t* dev ) { + const int result = usb_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_IN, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + &( ( libusb_hub_device_t* )dev->driver_data )->status, + sizeof( libusb_hub_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa0, + .length = sizeof( libusb_hub_full_status_t ), + }, + 10 /// FIXME: REPLACE WITH CONSTANT + ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get host status: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // handle not enough read + if ( dev->last_transfer != sizeof( libusb_hub_full_status_t ) ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to read hub status for %s\r\n", usb_get_description( dev ) ) + #endif + // return error + return EIO; + } + // return success + return 0; +} + +/** + * @fn int hub_get_port_status( libusb_device_t*, const uint8_t) + * @brief Wrapper to read port status + * @param dev + * @param port + * @return + */ +int hub_get_port_status( libusb_device_t* dev, const uint8_t port ) { + const int result = usb_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_IN, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + &( ( libusb_hub_device_t* )dev->driver_data )->port_status[ port ], + sizeof( libusb_hub_port_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa3, + .index = port + 1, + .length = sizeof( libusb_hub_port_full_status_t ), + }, + 10 + ); + // handle result wrong + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Fetching port status failed\r\n" ) + #endif + // return result + return result; + } + // handle wrong size + if ( dev->last_transfer != sizeof( libusb_hub_port_full_status_t ) ) { + // debug output + #if defined( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to read port %"PRIu8" status for %s. Received %"PRIu32" but expected %d\r\n", + port, usb_get_description( dev ), dev->last_transfer, sizeof( libusb_hub_port_full_status_t ) ) + #endif + // return io error + return EIO; + } + // return success + return 0; +} + +/** + * @fn int hub_change_port_feature(libusb_device_t*, libusb_hub_port_feature_t, uint8_t, bool) + * @brief Method to change port feature + * @param dev + * @param feature + * @param port + * @param set + * @return + */ +int hub_change_port_feature( + libusb_device_t* dev, + const libusb_hub_port_feature_t feature, + const uint8_t port, + const bool set +) { + return usb_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_OUT, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + NULL, + 0, + &( libusb_device_request_t ){ + .request = set + ? LIBUSB_DEVICE_REQUEST_SET_FEATURE + : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, + .type = 0x23, + .value = ( uint16_t )feature, + .index = port + 1, + }, + 10 /// FIXME: REPLACE WITH CONSTANT + ); +} + +/** + * @fn int hub_power_on(libusb_device_t*) + * @brief Method to power on hub + * @param dev + * @return + */ +int hub_power_on( libusb_device_t* dev ) { + // cache device data and descriptor locally + const libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; + const libusb_hub_descriptor_t* descriptor = device_data->descriptor; + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Powering up %s\r\n", usb_get_description( dev ) ) + #endif + // loop through all children and power on the port + for ( uint32_t child = 0; child < device_data->max_children; child++ ) { + #if defined( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Power up port %"PRIu32" of %s\r\n", child, usb_get_description( dev ) ) + #endif + // try to change port feature + [[maybe_unused]] const int result = hub_change_port_feature( + dev, + LIBUSB_HUB_PORT_FEATURE_POWER, + ( uint8_t )child, + true + ); + // handle error + if ( 0 != result ) { + // debug output only + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on port %"PRIu32" of %s: %s\r\n", + child, usb_get_description( dev ), strerror( result ) ) + #endif + } + } + // milliseconds to sleep + const long milliseconds = descriptor->power_good_delay * 2; + STARTUP_PRINT( "sleeping %ld milliseconds\r\n", milliseconds ) + // sleep a bit + nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + }, NULL ); + // return success + return 0; +} + +/** + * @fn int hub_port_reset(libusb_device_t*, uint8_t) + * @brief Wrapper to reset host port + * @param dev + * @param port + * @return + */ +int hub_port_reset( libusb_device_t* dev, const uint8_t port ) { + // cache driver data and status + libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; + const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; + uint32_t retry; + int result; + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Resetting port %"PRIu8" of device %s\r\n", port, usb_get_description( dev ) ) + #endif + // retry three times + for ( retry = 0; retry < 3; retry++ ) { + // try to reset + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_RESET, port, true ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to reset port %"PRIu8" of device %s\r\n", + port, usb_get_description( dev ) ) + #endif + // return result + return result; + } + // initialize timeout + uint32_t timeout = 0; + do { + // delay 20 milliseconds + const long milliseconds = 20; + nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + }, NULL ); + // read port data + result = hub_get_port_status( dev, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status of port %"PRIu8" from %s\r\n", + port, usb_get_description( dev ) ) + #endif + // return result + return result; + } + timeout++; + } while ( ! full_status->change.reset_changed && ! full_status->status.enabled && timeout < 10 ); + // handle timeout reached + if ( timeout >= 10 ) { + continue; + } + + if ( full_status->change.connected_changed || ! full_status->status.connected ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "connected_changed = %d, connected = %d\r\n", + full_status->change.connected_changed, full_status->status.connected ) + #endif + // return error + return ENXIO; + } + + // handle enabled + if ( full_status->status.enabled ) { + break; + } + } + // handle retry reached + if ( 3 == retry ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Cannot enable port %"PRIu8" on %s\r\n", + port, usb_get_description( dev ) ) + #endif + // return error + return EIO; + } + // clear reset + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to clear port %"PRIu8" reset of %s\r\n", + port, usb_get_description( dev ) ) + #endif + // return result + return result; + } + // return success + return 0; +} + +/** + * @fn int hub_port_connection_changed(libusb_device_t*, const uint8_t) + * @brief Handle hub connection changed + * @param dev + * @param port + * @return + */ +int hub_port_connection_changed( libusb_device_t* dev, const uint8_t port ) { + // cache driver data and status + libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; + libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; + // get hub port status + int result = hub_get_port_status( dev, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status (2) for %s with port %"PRIu8"\r\n", + usb_get_description( dev ), port + 1 ) + #endif + // return result + return result; + } + // change connection feature + result = hub_change_port_feature( dev, LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE, port, false ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear connection change on %s with port %"PRIu8"\r\n", + usb_get_description( dev ), port + 1 ) + #endif + // return result + return result; + } + // handle not connected and not enabled + if ( ( ! full_status->status.connected && ! full_status->status.enabled ) || device_data->children[ port ] ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Disconnected %s with port %"PRIu8"\r\n", + usb_get_description( dev ), port + 1 ) + #endif + /// FIXME: HANDLE! + } + // reset hub port + result = hub_port_reset( dev, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Could not reset port %"PRIu8" of %s for new device\r\n", + port + 1, usb_get_description( dev ) ) + #endif + // return result + return result; + } + // get hub port status + result = hub_get_port_status( dev, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status (3) for %s with port %"PRIu8"\r\n", + usb_get_description( dev ), port + 1 ) + #endif + // return result + return result; + } + libusb_speed_t speed = LIBUSB_SPEED_FULL; + if ( full_status->status.high_speed_attached ) { + speed = LIBUSB_SPEED_HIGH; + } else if ( full_status->status.low_speed_attached ) { + speed = LIBUSB_SPEED_LOW; + } + // attach new device + result = usb_attach_device( dev->number, port, speed ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach device: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // return success + return 0; + + + /* + * + if ((result = UsbAllocateDevice(&data->Children[port])) != OK) { + LOGF("HUB: Could not allocate a new device entry for %s.Port%d.\n", UsbGetDescription(device), port + 1); + return result; + } + + if ((result = HubPortGetStatus(device, port)) != OK) { + LOGF("HUB: Hub failed to get status (3) for %s.Port%d.\n", UsbGetDescription(device), port + 1); + return result; + } + + LOG_DEBUGF("HUB: %s.Port%d Status %x:%x.\n", UsbGetDescription(device), port + 1, *(u16*)&portStatus->Status, *(u16*)&portStatus->Change); + + if (portStatus->Status.HighSpeedAttatched) data->Children[port]->Speed = High; + else if (portStatus->Status.LowSpeedAttatched) data->Children[port]->Speed = Low; + else data->Children[port]->Speed = Full; + data->Children[port]->Parent = device; + data->Children[port]->PortNumber = port; + if ((result = UsbAttachDevice(data->Children[port])) != OK) { + LOGF("HUB: Could not connect to new device in %s.Port%d. Disabling.\n", UsbGetDescription(device), port + 1); + UsbDeallocateDevice(data->Children[port]); + data->Children[port] = NULL; + if (HubChangePortFeature(device, FeatureEnable, port, false) != OK) { + LOGF("HUB: Failed to disable %s.Port%d.\n", UsbGetDescription(device), port + 1); + } + return result; + } + return OK;*/ +} + +/** + * @fn int hub_check_connection(libusb_device_t*, uint8_t, bool) + * @brief Check hub for connection + * @param dev + * @param port + * @param is_roothub + * @return + */ +int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_roothub ) { + // cache hub device + libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; + const bool previously_connected = device_data->port_status[ port ].status.connected; + // get port status + int result = hub_get_port_status( dev, port ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to retrieve port status: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // cache full status + libusb_hub_port_full_status_t* port_status = &device_data->port_status[ port ]; + // handle connected to root device + STARTUP_PRINT( "dev->number = %"PRIu32" connected = %d, previously_connected = %d\r\n", + dev->number, port_status->status.connected ? 1 : 0, previously_connected ? 1 : 0 ) + // handle directly connected to root hub + if ( is_roothub && port_status->status.connected != previously_connected ) { + port_status->change.connected_changed = true; + } + // handle connection changed + if ( port_status->change.connected_changed ) { + STARTUP_PRINT( "Connected changed!\r\n" ) + hub_port_connection_changed( dev, port ); + } + if ( port_status->change.enabled_changed ) { + STARTUP_PRINT( "ENABLED CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear enable change for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( dev ) ) + #endif + } + + if ( ! port_status->status.enabled && port_status->status.connected && device_data->children[ port ] ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( + "%s. Port %d has been disabled but is connected. This can be caused by interference. Enabling it again\r\n", + usb_get_description( dev ), port + 1 ) + #endif + }/* + // This may indicate EM interference. + if (!portStatus->Status.Enabled && portStatus->Status.Connected && data->Children[port] != NULL) { + LOGF("HUB: %s.Port%d has been disabled, but is connected. This can be cause by interference. Reenabling!\n", UsbGetDescription(device), port + 1); + HubPortConnectionChanged(device, port); + }*/ + } + if ( port_status->status.suspended ) { + STARTUP_PRINT( "SUSPENDED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_SUSPEND, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to suspend port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( dev ) ) + #endif + } + } + if ( port_status->change.over_current_changed ) { + STARTUP_PRINT( "OVER CURRENT CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear over current for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( dev ) ) + #endif + } + // power on hub + result = hub_power_on( dev ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on device %s: %s\r\n", + usb_get_description( dev ), strerror( result ) ) + #endif + } + } + if ( port_status->change.reset_changed ) { + STARTUP_PRINT( "RESET CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + dev, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear reset for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( dev ) ) + #endif + } + } + // return success + return 0; +} + +/** + * @fn int hub_init(void) + * @brief Method to initialize hub + * @return + */ int hub_init( void ) { + // request root hub + libusb_device_t* roothub = usb_get_root_hub(); + // handle error + if ( ! roothub ) { + const int e = errno; + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to retrieve roothub: %s\r\n", strerror( errno ) ); + #endif + // return error + return e; + } + // check for multiple endpoints + if ( roothub->interfaces[ 0 ].endpoint_count != 1 ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Cannot enumerate hub with multiple endpoints: %"PRIu8"\r\n", + roothub->interfaces[ 0 ].endpoint_count ) + #endif + // return not supported + return ENOTSUP; + } + // handle only one output + if ( LIBUSB_DIRECTION_OUT == roothub->endpoints[ 0 ][ 0 ].endpoint_address.direction ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Cannot enumerate hub with only one output endpoint\r\n" ) + #endif + // return not supported + return ENOTSUP; + } + // handle no interrupt endpoint + if ( LIBUSB_TRANSFER_INTERRUPT != roothub->endpoints[ 0 ][ 0 ].attributes.transfer ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Cannot enumerate hub without interrupt endpoint\r\n" ) + #endif + // return not supported + return ENOTSUP; + } + // allocate driver data + roothub->driver_data = malloc( sizeof( libusb_hub_device_t ) ); + if ( ! roothub->driver_data ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate space for usb hub device\r\n" ) + #endif + // return enomem + return ENOMEM; + } + // clear out space + memset( roothub->driver_data, 0, sizeof( libusb_hub_device_t ) ); + // populate header of driver data + roothub->driver_data->data_size = sizeof( libusb_hub_device_t ); + roothub->driver_data->device_driver = DEVICE_DRIVER_HUB; + // cache usb hub device locally + libusb_hub_device_t* hub = ( libusb_hub_device_t* )roothub->driver_data; + // read hub descriptor + int result = hub_read_descriptor( roothub ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to fetch hub descriptor: %s\r\n", strerror( result ) ); + #endif + // return result + return result; + } + // get hub descriptor + const libusb_hub_descriptor_t* hub_descriptor = hub->descriptor; + // handle to many children + if ( MAX_CHILDREN_PER_DEVICE < hub_descriptor->port_count ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Hub %s is to big for this driver to handle. Only the first " + "%d ports will be used\r\n", usb_get_description( roothub ), + MAX_CHILDREN_PER_DEVICE ) + #endif + // set max children + hub->max_children = MAX_CHILDREN_PER_DEVICE; + } else { + hub->max_children = hub_descriptor->port_count; + } + // validate power switching mode + if ( + LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub_descriptor->attributes.power_switching_mode + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub_descriptor->attributes.power_switching_mode + ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unknown power type %d on %s\r\n", + hub_descriptor->attributes.power_switching_mode, + usb_get_description( roothub ) ) + #endif + // return not supported + return ENOTSUP; + } + // some debug output + #if defined( HUB_ENABLE_DEBUG ) + switch ( hub_descriptor->attributes.power_switching_mode ) { + case LIBUSB_HUB_PORT_CONTROL_GLOBAL: + STARTUP_PRINT( "Power mode is global\r\n" ) + break; + case LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL: + STARTUP_PRINT( "Power mode is individual\r\n" ) + break; + } + if ( hub_descriptor->attributes.compound ) { + STARTUP_PRINT( "Hub nature is compound\r\n" ) + } else { + STARTUP_PRINT( "Hub nature is standalone\r\n" ) + } + #endif + // validate over current protection + if ( + LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub_descriptor->attributes.over_current_protection + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub_descriptor->attributes.over_current_protection + ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unknown hub over current type %d on %s\r\n", + hub_descriptor->attributes.power_switching_mode, + usb_get_description( roothub ) ) + #endif + // return not supported + return ENOTSUP; + } + // some debug output + #if defined( HUB_ENABLE_DEBUG ) + switch ( hub_descriptor->attributes.over_current_protection ) { + case LIBUSB_HUB_PORT_CONTROL_GLOBAL: + STARTUP_PRINT( "Hub over current protection is global\r\n" ) + break; + case LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL: + STARTUP_PRINT( "Hub over current protection is individual\r\n" ) + break; + } + STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", hub_descriptor->power_good_delay * 2 ) + STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", hub_descriptor->maximum_hub_power * 2 ) + STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", hub_descriptor->port_count ) + #endif + // retrieve status + result = hub_get_status( roothub ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to fetch hub status for %s: %s\r\n", + usb_get_description( roothub ), strerror( result ) ) + #endif + // return result + return result; + } + // cache status locally + libusb_hub_full_status_t* status = &hub->status; + // some debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Hub power: %s\r\n", + !status->status.local_power ? "Good" : "Lost") + STARTUP_PRINT( "Hub over current condition: %s\r\n", + !status->status.over_current ? "No" : "Yes" ) + #endif + // power on hub + result = hub_power_on( roothub ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on hub!\r\n" ) + #endif + // return result + return result; + } + // fetch status again + result = hub_get_status( roothub ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get hub status for %s: %s\r\n", + usb_get_description( roothub ), strerror( result ) ) + #endif + // return result + return result; + } + // some debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Hub power: %s\r\n", + !status->status.local_power ? "Good" : "Lost") + STARTUP_PRINT( "Hub over current condition: %s\r\n", + !status->status.over_current ? "No" : "Yes" ) + #endif + + // check for connection + for ( uint8_t port = 0; port < hub->max_children; port++ ) { + STARTUP_PRINT( "Checking port %"PRIu8"\r\n", port ) + hub_check_connection( roothub, port, true ); + } + // return success return ENOSYS; } diff --git a/bolthur/server/usb/device/hub/hub.h b/bolthur/server/usb/device/hub/hub.h index 72d214ef..8fbba3af 100644 --- a/bolthur/server/usb/device/hub/hub.h +++ b/bolthur/server/usb/device/hub/hub.h @@ -20,8 +20,18 @@ #ifndef _HUB_H #define _HUB_H +#include "../../../libusb.h" + #define HUB_ENABLE_DEBUG 1 +int hub_read_descriptor( const libusb_device_t* ); +int hub_get_status( libusb_device_t* ); +int hub_get_port_status( libusb_device_t*, uint8_t ); +int hub_change_port_feature( libusb_device_t*, libusb_hub_port_feature_t, uint8_t, bool ); +int hub_power_on( libusb_device_t* ); +int hub_port_reset( libusb_device_t*, uint8_t ); +int hub_port_connection_changed( libusb_device_t*, uint8_t); +int hub_check_connection( libusb_device_t*, uint8_t, bool ); int hub_init( void ); #endif diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 7030d1c3..243bbe18 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -18,11 +18,14 @@ */ // system includes +#include #include #include // local includes #include "hub.h" #include "rpc.h" +// library includes +#include "../../../../library/usb/usb.h" /** * @fn int main(int, char*[]) @@ -40,6 +43,13 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } + // intialize usb library + STARTUP_PRINT( "Setup usb library\r\n" ) + if ( 0 != usb_init() ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( errno ) ); + return -1; + } + // setup hub interface STARTUP_PRINT( "Setup hub interface!\r\n" ) const int result = hub_init(); diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index ae7aaf68..9b24675b 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -3,6 +3,11 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/usbd\" bin_PROGRAMS = usbd usbd_SOURCES = \ + rpc/attach/device.c \ + rpc/control/message.c \ + rpc/get/description.c \ + rpc/get/descriptor.c \ + rpc/get/roothub.c \ rpc/handler/register.c \ rpc/handler/unregister.c \ rpc/init.c \ diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index 6e90c137..a127fdf0 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -53,12 +53,17 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { _syscall_rpc_set_ready( true ); // add device file - /// FIXME: PREPARE RPC AND FILL THEN DEVICE INFO STARTUP_PRINT( "Sending device to vfs\r\n" ) uint32_t device_info[] = { USBD_REGISTER_DEVICE_HANDLER, - USBD_UNREGISTER_DEVICE_HANDLER, }; - if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 2 ) ) { + USBD_UNREGISTER_DEVICE_HANDLER, + USBD_CONTROL_MESSAGE, + USBD_GET_DESCRIPTION, + USBD_GET_ROOTHUB, + USBD_GET_DESCRIPTOR, + USBD_ATTACH_DEVICE, + }; + if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 7 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/usbd/rpc.h b/bolthur/server/usb/usbd/rpc.h index e0438074..d184fb99 100644 --- a/bolthur/server/usb/usbd/rpc.h +++ b/bolthur/server/usb/usbd/rpc.h @@ -24,6 +24,11 @@ #include bool rpc_init( void ); +void rpc_attach_device( size_t, pid_t, size_t, size_t ); +void rpc_control_message( size_t, pid_t, size_t, size_t ); +void rpc_get_description( size_t, pid_t, size_t, size_t ); +void rpc_get_descriptor( size_t, pid_t, size_t, size_t ); +void rpc_get_roothub( size_t, pid_t, size_t, size_t ); void rpc_handler_register( size_t, pid_t, size_t, size_t ); void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/usb/usbd/rpc/attach/device.c b/bolthur/server/usb/usbd/rpc/attach/device.c new file mode 100644 index 00000000..80b58f4f --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/attach/device.c @@ -0,0 +1,123 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_attach_device(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler for attaching device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_attach_device( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_attach_device_t* message = ( usbd_attach_device_t* )request->container; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // find device + libusb_device_t* device = head; + while ( device ) { + // handle found + if ( device->number == message->parent_number ) { + break; + } + // go to next device + device = device->next; + } + // handle no device found + if ( ! device ) { + error.status = -EINVAL; + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + libusb_device_t* new_device; + // allocate new device + int result = usbd_allocate_device( &new_device, false ); + // handle error + if ( 0 != result ) { + error.status = -result; + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate speed into new device + new_device->speed = message->speed; + // allocate new device + // perform hcd control message + result = usbd_attach_device( new_device ); + // populate status and just copy over data from request + response->status = -result; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/control/message.c b/bolthur/server/usb/usbd/rpc/control/message.c new file mode 100644 index 00000000..3cd1d7ba --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/control/message.c @@ -0,0 +1,114 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler for device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_control_message( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_control_message_t* control_message = + ( usbd_control_message_t* )request->container; + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( + control_message->shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + // set error + error.status = -errno; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // transform shared memory into message + usb_control_message_t* message = ( usb_control_message_t* )shm_addr; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // perform hcd control message + const int result = usbd_control_message( + &message->device, + message->pipe_address, + message->buffer_length ? message->buffer : nullptr, + message->buffer_length, + &message->request, + message->timeout + ); + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // populate status and just copy over data from request + response->status = -result; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/description.c b/bolthur/server/usb/usbd/rpc/get/description.c new file mode 100644 index 00000000..1a074671 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/description.c @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_get_description(size_t, pid_t, size_t, size_t) + * @brief Get usb device description + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_description( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + const usbd_get_description_t* description = ( usbd_get_description_t* )request->container; + // get description with dummy device + const char* desc = usbd_get_description( + &(libusb_device_t) { + .status = description->status, + .descriptor = { + .usb_version = description->usb_version, + .product_id = description->product_id, + .vendor_id = description->vendor_id, + }, + .interfaces = { + { + .protocol = description->protocol, + .class = description->class, + } + } + } + ); + STARTUP_PRINT( "desc = %s\r\n", desc ) + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + + sizeof(char) * ( strlen( desc ) + 1 ); + STARTUP_PRINT( "response_size = %zu\r\n", response_size ) + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // clear out + memset( response, 0, response_size ); + // copy over description + response->status = 0; + strcpy( response->container, desc ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/descriptor.c b/bolthur/server/usb/usbd/rpc/get/descriptor.c new file mode 100644 index 00000000..239058f1 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/descriptor.c @@ -0,0 +1,116 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_get_descriptor(size_t, pid_t, size_t, size_t) + * @brief Get usb descriptor device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_descriptor( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_get_descriptor_t* control_message = + ( usbd_get_descriptor_t* )request->container; + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( + control_message->shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + // set error + error.status = -errno; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // transform shared memory into message + usb_descriptor_message_t* message = ( usb_descriptor_message_t* )shm_addr; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // perform get descriptor + const int result = usbd_get_descriptor( + &message->device, + message->type, + message->index, + message->lang_id, + message->buffer_length ? message->buffer : nullptr, + message->buffer_length, + message->minimum_length, + message->recipient + ); + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // populate status and just copy over data from request + response->status = -result; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/roothub.c b/bolthur/server/usb/usbd/rpc/get/roothub.c new file mode 100644 index 00000000..2586e534 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/roothub.c @@ -0,0 +1,120 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_get_roothub(size_t, pid_t, size_t, size_t) + * @brief Get usb roothub device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_roothub( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_get_roothub_t* control_message = + ( usbd_get_roothub_t* )request->container; + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( + control_message->shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + // set error + error.status = -errno; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // transform shared memory into message + libusb_device_t* dev = ( libusb_device_t* )shm_addr; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get root hub + libusb_device_t* roothub = usbd_get_root_hub(); + if ( ! roothub ) { + error.status = -EIO; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // copy over root hub + memcpy( dev, roothub, sizeof( libusb_device_t ) ); + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // populate status and just copy over data from request + response->status = 0; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/handler/register.c b/bolthur/server/usb/usbd/rpc/handler/register.c index 27b23b61..5491c371 100644 --- a/bolthur/server/usb/usbd/rpc/handler/register.c +++ b/bolthur/server/usb/usbd/rpc/handler/register.c @@ -33,6 +33,8 @@ * @param origin origin of the message * @param data_info data id * @param response_info response info + * + * @todo request real origin via syscall and check compare it to handler */ void rpc_handler_register( [[maybe_unused]] size_t type, diff --git a/bolthur/server/usb/usbd/rpc/handler/unregister.c b/bolthur/server/usb/usbd/rpc/handler/unregister.c index 949ff43c..59bc7739 100644 --- a/bolthur/server/usb/usbd/rpc/handler/unregister.c +++ b/bolthur/server/usb/usbd/rpc/handler/unregister.c @@ -33,6 +33,8 @@ * @param origin origin of the message * @param data_info data id * @param response_info response info + * + * @todo request real origin via syscall and check compare it to handler */ void rpc_handler_unregister( [[maybe_unused]] size_t type, diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c index 8abe2c0c..e7567ee9 100644 --- a/bolthur/server/usb/usbd/rpc/init.c +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -29,16 +29,46 @@ * @return */ bool rpc_init( void ) { + // register handler attaching a device + bolthur_rpc_bind( USBD_ATTACH_DEVICE, rpc_attach_device, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register attach device handler!\r\n" ) + return false; + } + // register handler control message + bolthur_rpc_bind( USBD_CONTROL_MESSAGE, rpc_control_message, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register control message handler!\r\n" ) + return false; + } + // register handler get description + bolthur_rpc_bind( USBD_GET_DESCRIPTION, rpc_get_description, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get description handler!\r\n" ) + return false; + } + // register handler get description + bolthur_rpc_bind( USBD_GET_DESCRIPTOR, rpc_get_descriptor, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get descriptor handler!\r\n" ) + return false; + } + // register handler get roothub + bolthur_rpc_bind( USBD_GET_ROOTHUB, rpc_get_roothub, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get roothub handler!\r\n" ) + return false; + } // register handler register bolthur_rpc_bind( USBD_REGISTER_DEVICE_HANDLER, rpc_handler_register, true ); if ( errno ) { - STARTUP_PRINT( "Unable to register handler register device handler!\r\n" ) + STARTUP_PRINT( "Unable to register register device handler!\r\n" ) return false; } // register handler unregister bolthur_rpc_bind( USBD_UNREGISTER_DEVICE_HANDLER, rpc_handler_unregister, true ); if ( errno ) { - STARTUP_PRINT( "Unable to register handler unregister device handler!\r\n" ) + STARTUP_PRINT( "Unable to register unregister device handler!\r\n" ) return false; } return true; diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index f41f12ce..d363e8fd 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -27,6 +27,8 @@ // local includes #include "usbd.h" // driver includes +#include + #include "../../libusb.h" #include "../../libhcd.h" @@ -1164,6 +1166,17 @@ int usbd_attach_root_hub( void ) { return 0; } +/** + * @fn libusb_device_t* usbd_get_root_hub(void) + * @brief Wrapper to get root hub + * @return + */ +libusb_device_t* usbd_get_root_hub( void ) { + // return first device or null if not set + return head; +} + + /** * @fn int usbd_init(void) * @brief Method to init usbd diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h index 714a846e..61ad41b2 100644 --- a/bolthur/server/usb/usbd/usbd.h +++ b/bolthur/server/usb/usbd/usbd.h @@ -41,6 +41,7 @@ int usbd_configure( libusb_device_t*, uint8_t ); const char* usbd_get_description( const libusb_device_t* ); int usbd_attach_device( libusb_device_t* ); int usbd_attach_root_hub( void ); +libusb_device_t* usbd_get_root_hub( void ); int usbd_init( void ); #endif From f101ccc4a6d0e416f73b441292f221c85461daa5 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 00:26:33 +0200 Subject: [PATCH 013/144] - Specified output in kernel rpc data a bit - Cleaned up usb library to reduce the message sizes - Replaced pass of libusb_device_t by pass of necessary stuff - Created new usbd endpoints for fetching endpoint and interface - Revised startup to startup usbd and all related daemons before starting hcd - --- bolthur/kernel/rpc/data.c | 5 +- bolthur/library/usb/usb.c | 310 +- bolthur/library/usb/usb.h | 11 +- bolthur/server/libhcd.h | 6 +- bolthur/server/libusb.h | 116 +- bolthur/server/platform/raspi/libhcd.h | 49 + bolthur/server/platform/raspi/usb/hcd/dwhci.c | 2629 ++++++++--------- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 15 +- .../platform/raspi/usb/hcd/dwhciroothub.c | 79 +- .../platform/raspi/usb/hcd/dwhciroothub.h | 2 +- bolthur/server/platform/raspi/usb/hcd/main.c | 2 +- .../server/platform/raspi/usb/hcd/response.c | 1 + .../server/platform/raspi/usb/hcd/response.h | 1 + .../usb/hcd/rpc/submit_control_message.c | 151 +- bolthur/server/terminal/render.c | 2 +- bolthur/server/usb/device/hub/Makefile.am | 2 +- bolthur/server/usb/device/hub/hub.h | 12 - bolthur/server/usb/device/hub/main.c | 35 +- bolthur/server/usb/device/hub/rpc.h | 1 + .../device/hub/{hub.c => rpc/hub/attach.c} | 718 +++-- bolthur/server/usb/device/hub/rpc/init.c | 7 + bolthur/server/usb/usbd/Makefile.am | 3 + bolthur/server/usb/usbd/call.c | 115 + bolthur/server/usb/usbd/call.h | 29 + bolthur/server/usb/usbd/main.c | 32 +- bolthur/server/usb/usbd/rpc.h | 2 + bolthur/server/usb/usbd/rpc/attach/device.c | 4 + bolthur/server/usb/usbd/rpc/control/message.c | 36 +- bolthur/server/usb/usbd/rpc/get/description.c | 33 +- bolthur/server/usb/usbd/rpc/get/descriptor.c | 23 +- bolthur/server/usb/usbd/rpc/get/endpoint.c | 106 + bolthur/server/usb/usbd/rpc/get/interface.c | 105 + bolthur/server/usb/usbd/rpc/get/roothub.c | 33 +- .../server/usb/usbd/rpc/handler/register.c | 97 +- .../server/usb/usbd/rpc/handler/unregister.c | 95 +- bolthur/server/usb/usbd/rpc/init.c | 18 +- bolthur/server/usb/usbd/usbd.c | 138 +- bolthur/server/usb/usbd/usbd.h | 4 + config/ini/raspi/bcm2709/stage3.ini | 20 +- notes-usb.md | 29 + 40 files changed, 2862 insertions(+), 2214 deletions(-) rename bolthur/server/usb/device/hub/{hub.c => rpc/hub/attach.c} (55%) create mode 100644 bolthur/server/usb/usbd/call.c create mode 100644 bolthur/server/usb/usbd/call.h create mode 100644 bolthur/server/usb/usbd/rpc/get/endpoint.c create mode 100644 bolthur/server/usb/usbd/rpc/get/interface.c create mode 100644 notes-usb.md diff --git a/bolthur/kernel/rpc/data.c b/bolthur/kernel/rpc/data.c index ec5500b1..79143908 100644 --- a/bolthur/kernel/rpc/data.c +++ b/bolthur/kernel/rpc/data.c @@ -22,7 +22,6 @@ #include "../lib/string.h" #include "../lib/stdlib.h" #include "data.h" -#include "../panic.h" #include "../mm/phys.h" #include "../mm/virt.h" #if defined( PRINT_RPC ) @@ -176,7 +175,7 @@ int rpc_data_queue_add( virt_unmap_temporary( mailbox, PAGE_SIZE ); // debug output #if defined( PRINT_RPC ) - DEBUG_OUTPUT( "Mailbox full!\r\n" ) + DEBUG_OUTPUT( "Mailbox full of %d!\r\n", target ) #endif return ENOMEM; } @@ -191,7 +190,7 @@ int rpc_data_queue_add( virt_unmap_temporary( mailbox, PAGE_SIZE ); // debug output #if defined( PRINT_RPC ) - DEBUG_OUTPUT( "Mailbox full!\r\n" ) + DEBUG_OUTPUT( "Mailbox full of %d!\r\n", target ) #endif return ENOMEM; } diff --git a/bolthur/library/usb/usb.c b/bolthur/library/usb/usb.c index 65ae67c0..38db6dc4 100644 --- a/bolthur/library/usb/usb.c +++ b/bolthur/library/usb/usb.c @@ -54,12 +54,12 @@ int usb_init( void ) { } /** - * @fn const char* usb_get_description(const libusb_device_t*) + * @fn const char* usb_get_description(uint32_t) * @brief Wrapper to get description for device - * @param dev + * @param device_number * @return */ -const char* usb_get_description( const libusb_device_t* dev ) { +const char* usb_get_description( const uint32_t device_number ) { // local buffer for description static char buffer[ 256 ]; // debug message @@ -82,12 +82,7 @@ const char* usb_get_description( const libusb_device_t* dev ) { // clear out memset( request, 0, sizeof( *request ) ); // copy over necessary data - request->status = dev->status; - request->usb_version = dev->descriptor.usb_version; - request->product_id = dev->descriptor.product_id; - request->vendor_id = dev->descriptor.vendor_id; - request->protocol = dev->interfaces[ 0 ].protocol; - request->class = dev->interfaces[ 0 ].class; + request->device_number = device_number; // perform ioctl command // perform request const int result = ioctl( @@ -119,23 +114,29 @@ const char* usb_get_description( const libusb_device_t* dev ) { } /** - * @fn int usb_control_message(libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t) + * @fn int usb_control_message(uint32_t, libusb_transfer_t, libusb_direction_t, void*, size_t, const libusb_device_request_t*, size_t, libusb_transfer_error_t*, uint32_t*) * @brief Wrapper to perform usb control message - * @param dev - * @param pipe + * @param device_number + * @param transfer + * @param direction * @param buffer * @param buffer_length * @param request * @param timeout + * @param error + * @param last_transfer * @return */ int usb_control_message( - libusb_device_t* dev, - const libusb_pipe_address_t pipe, + const uint32_t device_number, + const libusb_transfer_t transfer, + const libusb_direction_t direction, void* buffer, const size_t buffer_length, const libusb_device_request_t* request, - const size_t timeout + const size_t timeout, + libusb_transfer_error_t* error, + uint32_t* last_transfer ) { // debug output #if defined( LIBUSB_ENABLE_DEBUG ) @@ -168,12 +169,14 @@ int usb_control_message( } usb_control_message_t* message = ( usb_control_message_t* )shm_addr; // populate real message in shared memory - memcpy( &message->device, dev, sizeof( libusb_device_t ) ); - memcpy( &message->pipe_address, &pipe, sizeof( pipe ) ); + message->device_number = device_number; + message->transfer = transfer; + message->direction = direction; + message->buffer_length = buffer_length; memcpy( &message->request, request, sizeof( *request ) ); message->buffer_length = buffer_length; message->timeout = timeout; - if ( LIBUSB_DIRECTION_OUT == pipe.direction && buffer ) { + if ( LIBUSB_DIRECTION_OUT == direction && buffer ) { memcpy( &message->buffer, buffer, buffer_length ); } // allocate request @@ -215,11 +218,15 @@ int usb_control_message( // return eio return EIO; } + // populate error and last transfer + *error = message->error; + *last_transfer = message->last_transfer; // response is equal to input - if ( message->device.error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { + if ( *error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { // debug output #if defined( LIBUSB_ENABLE_DEBUG ) - STARTUP_PRINT( "Message to %s timeout reached\r\n", usb_get_description( dev ) ) + STARTUP_PRINT( "Message to %s timeout reached\r\n", + usb_get_description( device_number ) ) #endif // detach shared memory _syscall_memory_shared_detach( shm_id ); @@ -229,12 +236,9 @@ int usb_control_message( return ETIMEDOUT; } // copy over data - if ( LIBUSB_DIRECTION_IN == pipe.direction && buffer ) { + if ( LIBUSB_DIRECTION_IN == direction && buffer ) { memcpy( buffer, message->buffer, buffer_length ); } - // copy over static fields into device populated via shared memory - dev->error = message->device.error; - dev->last_transfer = message->device.last_transfer; // detach shared memory _syscall_memory_shared_detach( shm_id ); // free control message @@ -248,39 +252,19 @@ int usb_control_message( * @brief Wrapper to get root hub * @return */ -libusb_device_t* usb_get_root_hub( void ) { +int usb_get_root_hub( uint32_t* device_number ) { // debug output #if defined( LIBUSB_ENABLE_DEBUG ) STARTUP_PRINT( "firing usb get root hub\r\n" ) #endif - // allocate shared memory - const size_t shm_id = _syscall_memory_shared_create( sizeof( libusb_device_t ) ); - // handle error - if ( errno ) { - const int e = errno; - // debug output - #if defined( LIBUSB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) - #endif - // return error - errno = e; - return nullptr; - } - // attach shared memory - void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); - // handle error - if ( errno ) { - const int e = errno; - // debug output + // handle invalid parameter + if ( ! device_number ) { #if defined( LIBUSB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + STARTUP_PRINT( "Invalid parameter passed!\r\n" ) #endif - // return error - errno = e; - return nullptr; + // return einval + return EINVAL; } - // clear out - memset( shm_addr, 0, sizeof( libusb_device_t ) ); // allocate request usbd_get_roothub_t* request = malloc( sizeof( *request ) ); if ( ! request ) { @@ -288,16 +272,11 @@ libusb_device_t* usb_get_root_hub( void ) { #if defined( LIBUSB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to allocate request\r\n" ) #endif - // detach shared memory - _syscall_memory_shared_detach( shm_id ); // return error - errno = ENOMEM; - return nullptr; + return ENOMEM; } // clear out everything memset( request, 0, sizeof( *request ) ); - // populate shm_id - request->shm_id = shm_id; // perform request const int result = ioctl( fd_usbd, @@ -314,38 +293,23 @@ libusb_device_t* usb_get_root_hub( void ) { #if defined( LIBUSB_ENABLE_DEBUG ) STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); #endif - // detach shared memory - _syscall_memory_shared_detach( shm_id ); // free request free( request ); // return eio - errno = EIO; - return nullptr; - } - // allocate device locally - libusb_device_t* dev = malloc( sizeof( *dev ) ); - // handle error - if ( ! dev ) { - #if defined( LIBUSB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to allocate space for return\r\n" ) - #endif - errno = ENOMEM; - return nullptr; + return EIO; } - // copy over - memcpy( dev, shm_addr, sizeof( *dev ) ); - // detach shared memory - _syscall_memory_shared_detach( shm_id ); + // copy over response + memcpy( device_number, request, sizeof ( uint32_t ) ); // free request free( request ); // return device - return dev; + return 0; } /** - * @fn int usb_get_descriptor(libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t) + * @fn int usb_get_descriptor(uint32_t, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t) * @brief Wrapper to get usb descriptor - * @param dev + * @param device_number * @param type * @param index * @param lang_id @@ -356,7 +320,7 @@ libusb_device_t* usb_get_root_hub( void ) { * @return */ int usb_get_descriptor( - const libusb_device_t* dev, + const uint32_t device_number, const libusb_descriptor_type_t type, const uint8_t index, const uint16_t lang_id, @@ -396,7 +360,7 @@ int usb_get_descriptor( } usb_descriptor_message_t* message = ( usb_descriptor_message_t* )shm_addr; // populate real message in shared memory - memcpy( &message->device, dev, sizeof( libusb_device_t ) ); + message->device_number = device_number; message->type = type; message->index = index; message->lang_id = lang_id; @@ -458,14 +422,16 @@ int usb_get_descriptor( } /** - * @fn int usb_attach_device(uint32_t, uint32_t) + * @fn int usb_attach_device(uint32_t, uint32_t, libusb_speed_t) * @brief Method to attach a new discovered device * @param parent_number * @param port_number * @param speed * @return + * + * @todo return child id */ -int usb_attach_device( const uint32_t parent_number, const uint32_t port_number, libusb_speed_t speed ) { +int usb_attach_device( const uint32_t parent_number, const uint32_t port_number, const libusb_speed_t speed ) { // debug message #if defined( LIBUSB_ENABLE_DEBUG ) STARTUP_PRINT( "Attaching device %"PRIu32" to %"PRIu32"\r\n", @@ -508,5 +474,187 @@ int usb_attach_device( const uint32_t parent_number, const uint32_t port_number, free( request ); return EIO; } + // free request + free( request ); + // return success + return 0; +} + +/** + * @fn int usb_register_handler(libusb_interface_class_t) + * @brief Method to attach a new discovered device + * @param type + * @return + */ +int usb_register_handler( const libusb_interface_class_t type ) { + const pid_t pid = getpid(); + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Registering pid %d for type %d\r\n", pid, type ) + #endif + // allocate device + usbd_register_device_handler_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->type = type; + request->handler = pid; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_REGISTER_HANDLER, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // free request + free( request ); + // return success + return 0; +} + +/** + * @fn int usb_get_endpoint(uint32_t, uint32_t, uint32_t, libusb_endpoint_descriptor_t*) + * @brief Helper to get usb endpoint data + * @param device_number + * @param interface_number + * @param endpoint_number + * @param descriptor + * @return + */ +int usb_get_endpoint( + const uint32_t device_number, + const uint32_t interface_number, + const uint32_t endpoint_number, + libusb_endpoint_descriptor_t* descriptor +) { + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Get endpoint information\r\n" ) + #endif + // allocate device + usbd_get_endpoint_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->device_number = device_number; + request->interface_number = interface_number; + request->endpoint_number = endpoint_number; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_ENDPOINT, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // copy over endpoint data + memcpy( descriptor, request, sizeof( *descriptor ) ); + // free request + free( request ); + // return success + return 0; +} + +/** + * @fn int usb_get_interface(uint32_t, uint32_t, libusb_interface_descriptor_t*) + * @brief Wrapper to get interface data + * @param device_number + * @param interface_number + * @param descriptor + * @return + */ +int usb_get_interface( + const uint32_t device_number, + const uint32_t interface_number, + libusb_interface_descriptor_t* descriptor +) { + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Get interface" ) + #endif + // allocate device + usbd_get_interface_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->device_number = device_number; + request->interface_number = interface_number; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_INTERFACE, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // copy over data + memcpy( descriptor, request, sizeof( *descriptor ) ); + // free request + free( request ); + // return success return 0; } diff --git a/bolthur/library/usb/usb.h b/bolthur/library/usb/usb.h index 3ebf3181..5a829c13 100644 --- a/bolthur/library/usb/usb.h +++ b/bolthur/library/usb/usb.h @@ -25,10 +25,13 @@ #define LIBUSB_ENABLE_DEBUG 1 int usb_init( void ); -const char* usb_get_description( const libusb_device_t* ); -int usb_control_message( libusb_device_t*, libusb_pipe_address_t, void*, size_t, const libusb_device_request_t*, size_t ); -libusb_device_t* usb_get_root_hub( void ); -int usb_get_descriptor( const libusb_device_t*, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t ); +int usb_control_message( uint32_t, libusb_transfer_t, libusb_direction_t, void*, size_t, const libusb_device_request_t*, size_t, libusb_transfer_error_t*, uint32_t* ); +const char* usb_get_description( uint32_t ); +int usb_get_descriptor( uint32_t, libusb_descriptor_type_t, uint8_t, uint16_t, void*, size_t, size_t, uint8_t ); int usb_attach_device( uint32_t, uint32_t, libusb_speed_t ); +int usb_register_handler( libusb_interface_class_t ); +int usb_get_endpoint( uint32_t, uint32_t, uint32_t, libusb_endpoint_descriptor_t* ); +int usb_get_interface( uint32_t, uint32_t, libusb_interface_descriptor_t* ); +int usb_get_root_hub( uint32_t* ); #endif diff --git a/bolthur/server/libhcd.h b/bolthur/server/libhcd.h index ffa565c2..9be96b7e 100644 --- a/bolthur/server/libhcd.h +++ b/bolthur/server/libhcd.h @@ -32,7 +32,11 @@ typedef struct { } hcd_submit_control_message_t; typedef struct { - libusb_device_t device; + uint32_t device_number; + uint32_t parent_device_number; + uint32_t port_number; + uint32_t last_transfer; + libusb_transfer_error_t error; libusb_pipe_address_t pipe_address; libusb_device_request_t request; size_t buffer_length; diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index d0874fd7..bbcff60d 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -375,6 +375,7 @@ typedef struct libusb_device { pid_t device_child_reset_handler; pid_t device_check_connection_handler; + /// FIXME: REPLACE POINTER TO FUNCTIONS BY PID CALLS /** Handler for detaching the device. The device driver should not issue further requests to the device. */ void ( *device_detached )( libusb_device_t* device ) __aligned( 4 ); /** Handler for deallocation of the device. All memory in use by the device driver should be deallocated. */ @@ -493,8 +494,8 @@ typedef struct { libusb_hub_full_status_t status; libusb_hub_descriptor_t* descriptor; uint32_t max_children; - libusb_hub_port_full_status_t port_status[ MAX_CHILDREN_PER_DEVICE ]; - libusb_device_t* children[ MAX_CHILDREN_PER_DEVICE ]; + libusb_hub_port_full_status_t port_status[ 255 ]; + uint32_t children[ 255 ]; } libusb_hub_device_t; typedef enum { @@ -505,59 +506,86 @@ typedef enum { // enable warnings again #pragma GCC diagnostic pop +// device paths #define USBD_DEVICE_PATH "/dev/usb/usbd" +#define HUB_DEVICE_PATH "/dev/usb/hub" + +// hub rpc +#define HUB_ATTACH RPC_CUSTOM_START + +// usbd rpc +#define USBD_REGISTER_HANDLER RPC_CUSTOM_START +#define USBD_UNREGISTER_HANDLER USBD_REGISTER_HANDLER + 1 +#define USBD_GET_DESCRIPTOR USBD_UNREGISTER_HANDLER + 1 +#define USBD_GET_ENDPOINT USBD_GET_DESCRIPTOR + 1 +#define USBD_GET_INTERFACE USBD_GET_ENDPOINT + 1 +#define USBD_GET_DESCRIPTION USBD_GET_INTERFACE + 1 +#define USBD_CONTROL_MESSAGE USBD_GET_DESCRIPTION + 1 +#define USBD_ATTACH_DEVICE USBD_CONTROL_MESSAGE + 1 +#define USBD_GET_ROOTHUB USBD_ATTACH_DEVICE + 1 + +// generic usb rpc structures +typedef struct { + uint32_t parent_device_number; + uint32_t device_number; + uint32_t interface_number; +} usb_generic_attach_t; -#define USBD_REGISTER_DEVICE_HANDLER RPC_CUSTOM_START -#define USBD_UNREGISTER_DEVICE_HANDLER USBD_REGISTER_DEVICE_HANDLER + 1 -#define USBD_CONTROL_MESSAGE USBD_UNREGISTER_DEVICE_HANDLER + 1 -#define USBD_GET_DESCRIPTION USBD_CONTROL_MESSAGE + 1 -#define USBD_GET_ROOTHUB USBD_GET_DESCRIPTION + 1 -#define USBD_GET_DESCRIPTOR USBD_GET_ROOTHUB + 1 -#define USBD_ATTACH_DEVICE USBD_GET_DESCRIPTOR + 1 +// usbd rpc structures +typedef struct { + libusb_interface_class_t type; + pid_t handler; +} usbd_register_device_handler_t; -// external rpc declarations +typedef struct { + libusb_interface_class_t type; + pid_t handler; +} usbd_unregister_device_handler_t; -typedef enum { - DEVICE_HANDLER_TYPE_DETACHED = 1, - DEVICE_HANDLER_TYPE_DEALLOCATE = 2, - DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE = 3, - DEVICE_HANDLER_TYPE_CHILD_DETACHED = 4, - DEVICE_HANDLER_TYPE_CHILD_RESET = 5, - DEVICE_HANDLER_TYPE_CHECK_CONNECTION = 6, -} device_handler_type_t; +typedef struct { + size_t shm_id; +} usbd_get_descriptor_t; typedef struct { uint32_t device_number; - device_handler_type_t type; - pid_t handler; -} usbd_register_device_handler_t; + libusb_descriptor_type_t type; + uint8_t index; + uint16_t lang_id; + size_t buffer_length; + size_t minimum_length; + uint8_t recipient; + uint8_t buffer[]; +} usb_descriptor_message_t; typedef struct { + // parameters uint32_t device_number; - device_handler_type_t type; -} usbd_unregister_device_handler_t; + uint32_t interface_number; + uint32_t endpoint_number; + // space for return object + libusb_endpoint_descriptor_t descriptor; +} usbd_get_endpoint_t; typedef struct { - size_t shm_id; -} usbd_control_message_t; + // parameters + uint32_t device_number; + uint32_t interface_number; + // space for return + libusb_interface_descriptor_t interface; +} usbd_get_interface_t; typedef struct { - libusb_device_status_t status; - uint16_t usb_version; - uint16_t vendor_id; - uint16_t product_id; - libusb_interface_class_t class; - uint8_t protocol; + uint32_t device_number; char buffer[ 256 ]; } usbd_get_description_t; typedef struct { size_t shm_id; -} usbd_get_roothub_t; +} usbd_control_message_t; typedef struct { - size_t shm_id; -} usbd_get_descriptor_t; + uint32_t device_number; +} usbd_get_roothub_t; typedef struct { uint32_t parent_number; @@ -566,23 +594,15 @@ typedef struct { } usbd_attach_device_t; typedef struct { - libusb_device_t device; - libusb_pipe_address_t pipe_address; - libusb_device_request_t request; + uint32_t device_number; + libusb_transfer_t transfer; + libusb_direction_t direction; size_t buffer_length; + libusb_device_request_t request; size_t timeout; + uint32_t last_transfer; + libusb_transfer_error_t error; uint8_t buffer[]; } usb_control_message_t; -typedef struct { - libusb_device_t device; - libusb_descriptor_type_t type; - uint8_t index; - uint16_t lang_id; - size_t buffer_length; - size_t minimum_length; - uint8_t recipient; - uint8_t buffer[]; -} usb_descriptor_message_t; - #endif diff --git a/bolthur/server/platform/raspi/libhcd.h b/bolthur/server/platform/raspi/libhcd.h index 3ceb90e6..6aff2e3c 100644 --- a/bolthur/server/platform/raspi/libhcd.h +++ b/bolthur/server/platform/raspi/libhcd.h @@ -104,14 +104,27 @@ #define HCD_DWHCI_CORE_RESET_AHB_IDLE ( 1 << 31 ) // dwhci cfg2 values #define HCD_DWHCI_CORE_HW_CFG2_OP_MODE( reg ) ( ( ( reg ) >> 0 ) & 7 ) +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_HNP_SRP_CAPABLE 0 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_ONLY_CAPABLE 1 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_HNP_SRP_CAPABLE 2 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_CAPABLE_HOST 5 +#define HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 #define HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE( reg ) ( ( ( reg ) >> 3 ) & 3 ) +#define HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE_SLAVE_ONLY 0 +#define HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE_EXTERNAL_DMA 1 +#define HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE_INTERNAL_DMA 2 #define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( reg ) ( ( ( reg ) >> 6 ) & 3 ) #define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 #define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_UTMI 1 #define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI 2 #define HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_UTMI_ULPI 3 #define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( reg ) ( ( ( reg ) >> 8 ) & 3 ) +#define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_PHYSICAL0 0 #define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED 1 +#define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_PHYSICAL1 2 +#define HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_PHYSICAL2 3 #define HCD_DWHCI_CORE_HW_CFG2_NUM_HOST_CHANNELS( reg ) ( ( ( ( reg ) >> 14 ) & 0xF ) + 1 ) // dwhci host cfg values #define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_SHIFT 0 @@ -119,6 +132,8 @@ #define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_30_60_MHZ 0 #define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ 1 #define HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_6_MHZ 2 +#define HCD_DWHCI_HOST_CFG_FSLS_ONLY ( 1 << 2 ) +#define HCD_DWHCI_HOST_CFG_ENABLE_DMA_DESCRIPTOR ( 1 << 23 ) // dwhci host port values #define HCD_DWHCI_HOST_PORT_CONNECT ( 1 << 0 ) #define HCD_DWHCI_HOST_PORT_CONNECT_CHANGED ( 1 << 1 ) @@ -158,4 +173,38 @@ #define HCD_DWHCI_POWER_REGISTER_PHY_SLEEPING ( 1 << 6 ) #define HCD_DWHCI_POWER_REGISTER_DEEP_SLEEP ( 1 << 7 ) +// channel transfer register +#define HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_TRANSFER_SIZE( val ) ( ( val ) & 0x7ffff ) +#define HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( val ) ( ( ( val ) >> 19 ) & 0x3ff ) + +// characteristics +#define HCD_DWHCI_CHAN_CHARACTER_MAXIMUM_PACKET_SIZE( val ) ( ( val ) & 0x7ff ) +#define HCD_DWHCI_CHAN_CHARACTER_END_POINT_NUMBER( val ) ( ( ( val ) & 0xf ) << 11 ) +#define HCD_DWHCI_CHAN_CHARACTER_END_POINT_DIRECTION( val ) ( ( ( val ) & 0x1 ) << 15 ) +#define HCD_DWHCI_CHAN_CHARACTER_LOW_SPEED( val ) ( ( ( val ) & 0x1 ) << 17 ) +#define HCD_DWHCI_CHAN_CHARACTER_TYPE( val ) ( ( ( val ) & 0x3 ) << 18 ) +#define HCD_DWHCI_CHAN_CHARACTER_PACKETS_PER_FRAME( val ) ( ( ( val ) & 0x3 ) << 20 ) +#define HCD_DWHCI_CHAN_CHARACTER_DEVICE_ADDRESS( val ) ( ( ( val ) & 0x7f ) << 22 ) +#define HCD_DWHCI_CHAN_CHARACTER_ODD_FRAME( val ) ( ( ( val ) & 0x1 ) << 29 ) +#define HCD_DWHCI_CHAN_CHARACTER_DISABLE( val ) ( ( ( val ) & 0x1 ) << 30 ) +#define HCD_DWHCI_CHAN_CHARACTER_ENABLE( val ) ( ( ( val ) & 0x1 ) << 31 ) +// split control +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_PORT_ADDRESS( val ) ( ( val ) & 0x7f ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_HUB_ADDRESS( val ) ( ( ( val ) & 0x7f ) << 7 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_TRANSACTION_POSITION( val ) ( ( ( val ) & 0x3 ) << 14 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_COMPLETE_SPLIT( val ) ( ( ( val ) & 0x1 ) << 16 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_SPLIT_ENABLE( val ) ( ( ( val ) & 0x1 ) << 31 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_PORT_ADDRESS( val ) ( ( val ) & 0x7f ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_HUB_ADDRESS( val ) ( ( ( val ) & 0x7f ) << 7 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_TRANSACTION_POSITION( val ) ( ( ( val ) & 0x3 ) << 14 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_COMPLETE_SPLIT( val ) ( ( ( val ) & 0x1 ) << 16 ) +#define HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_SPLIT_ENABLE ( 1 << 31 ) +// xfer +#define HCD_DWHCI_CHAN_XFER_SIZE_TRANSFER_SIZE( val ) ( ( val ) & 0x7ffff ) +#define HCD_DWHCI_CHAN_XFER_SIZE_PACKET_COUNT( val ) ( ( ( val ) & 0x3ff ) << 19 ) +#define HCD_DWHCI_CHAN_XFER_SIZE_PACKET_ID( val ) ( ( ( val ) & 0x3 ) << 29 ) + +// core ctrl stuff +#define HCD_DWHCI_CORE_CTRL_HOST_SET_NP_ENABLE ( 1 << 10 ) + #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index 952b326b..9e5a553e 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -26,6 +26,9 @@ #include "util.h" #include "response.h" // driver includes +#include +#include + #include "../../libhcd.h" #include "../../libiomem.h" #include "../../libperipheral.h" @@ -36,19 +39,21 @@ */ int fd_iomem = -1; +void* databuffer = nullptr; + /** - * @fn uint32_t dwhci_query_vendor(uint32_t*) - * @brief Helper to query vendor - * @param destination pointer to write vendor id to - * @return operation response + * @brief Helper to read a port + * @param port + * @param value + * @return */ -response_t dwhci_query_vendor( uint32_t* destination ) { +response_t dwhci_read_port( const uint32_t port, uint32_t* value ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Query vendor information\r\n" ) + STARTUP_PRINT( "Query port information\r\n" ) #endif // validate parameter - if ( ! destination ) { + if ( ! value ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Invalid parameters passed!\r\n" ) @@ -69,7 +74,7 @@ response_t dwhci_query_vendor( uint32_t* destination ) { } // overwrite register to read sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_VENDOR_ID; + sequence[ 0 ].offset = port; // perform request const int result = ioctl( fd_iomem, @@ -92,13 +97,672 @@ response_t dwhci_query_vendor( uint32_t* destination ) { return HCD_RESPONSE_ERROR_IO; } // push read value into destination - *destination = sequence[ 0 ].value; + *value = sequence[ 0 ].value; + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @brief Helper to write to a port + * @param port + * @param value + * @return + */ +response_t dwhci_write_port( const uint32_t port, const uint32_t value ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Query port information\r\n" ) + #endif + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // overwrite register to read + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = port; + sequence[ 0 ].value = value; + // perform request + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Querying vendor information failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @fn response_t dwhci_transmit_channel(uint8_t, void*) + * @brief Transmit channel operation + * @param channel + * @param buffer + * @return + */ +response_t dwhci_transmit_channel( const uint8_t channel, void* buffer ) { + // translate buffer to physical bus address + const uintptr_t phys = _syscall_memory_translate_bus( ( uintptr_t )buffer, 1 ); + if ( errno ) { + return HCD_RESPONSE_ERROR_IO; + } + // allocate sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 5, &sequence_size ); + if ( ! sequence ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + #endif + // return memory error + return HCD_RESPONSE_ERROR_MEMORY; + } + + // read split control with unset of complete split + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ); + sequence[ 0 ].value = ( uint32_t )~( HCD_DWHCI_CHAN_SPLIT_CONTROL_COMPLETE_SPLIT( true ) ); + // write back previous read to split control + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_PREVIOUS_READ; + sequence[ 1 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ); + // set dma address + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 2 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_HOST_CHAN_DMA_ADDR( channel ); + sequence[ 2 ].value = phys; + // read characteristic with unset of packets per frame, enable and disable + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 3 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 3 ].value = ~( + ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_PACKETS_PER_FRAME( 0xffffffff ) + | ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ) + | ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_DISABLE( 1 ) + ); + // write characteristic back with 1 packet per frame and enable 1 + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 4 ].value = ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_PACKETS_PER_FRAME( 1 ) + | ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ); + // write to io + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Transmit channel sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return io error + return HCD_RESPONSE_ERROR_IO; + } + // free sequence + free( sequence ); + // return success + return HCD_RESPONSE_OK; +} + +/** + * @brief Translate channel interrupt to error + * @param error + * @param channel + * @param completed + * @return + */ +response_t dwhci_channel_interrupt_to_error( libusb_transfer_error_t* error, const uint8_t channel, const bool completed ) { + uint32_t interrupt; + response_t result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), &interrupt ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + result = HCD_RESPONSE_OK; + if ( interrupt & HCD_CHANNEL_INTERRUPT_AHB_ERROR ) { + STARTUP_PRINT( "AHB ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_AHB_ERROR; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_STALL ) { + STARTUP_PRINT( "STALL ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_STALL; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_NEGATIVE_ACKNOWLEDGEMENT ) { + STARTUP_PRINT( "NEGATIVE ACK ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_NO_ACKNOWLEDGE; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_ACKNOWLEDGEMENT ) { + STARTUP_PRINT( "ACK ERROR\r\n" ) + result = HCD_RESPONSE_ERROR_TIMEOUT; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_NOT_YET ) { + STARTUP_PRINT( "NOT_YET ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_NOT_YET_ERROR; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_BABBLE_ERROR ) { + STARTUP_PRINT( "BABBLE_ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_BABBLE; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_FRAME_OVERRUN ) { + STARTUP_PRINT( "OVERRUN ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_DATA_TOGGLE_ERROR ) { + STARTUP_PRINT( "DATA_TOGGLE_ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_BIT_ERROR; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_TRANSACTION_ERROR ) { + STARTUP_PRINT( "TRANSACTION_ERROR\r\n" ) + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + return HCD_RESPONSE_ERROR_UNKNOWN; + } + if ( !( interrupt & HCD_CHANNEL_INTERRUPT_TRANSFER_COMPLETE ) && completed ) { + STARTUP_PRINT( "COMPLETED BUT FLAG NOT COMPLETED\r\n" ) + result = HCD_RESPONSE_ERROR_TIMEOUT; + } + return result; +} + +static void custom_nanosleep( const struct timespec* rqtp ) { + if ( 0 > rqtp->tv_nsec ) { + errno = EINVAL; + return; + } + // get clock frequency + size_t frequency = _syscall_timer_frequency(); + // calculate second timeout + size_t timeout = ( size_t )( rqtp->tv_sec * frequency ); + size_t tick; + // add nanosecond offset + timeout += ( size_t )( ( double )rqtp->tv_nsec * ( double )frequency / 1000000000.0 ); + // add tick count to get an end time + timeout += _syscall_timer_tick_count(); + // loop until timeout is reached + while ( ( tick = _syscall_timer_tick_count() ) < timeout ) { + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif + __asm__ __volatile__( "nop" ); + } + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif +} + +response_t dwhci_channel_send_wait_one( + libusb_transfer_error_t* error, + const uint8_t channel, + void* buffer, + const uint32_t buffer_offset, + [[maybe_unused]] libusb_speed_t speed +) { + uint32_t tries, global_tries, actual_tries; + + for ( + global_tries = 0, actual_tries = 0; + global_tries < 3 && actual_tries < 10; + global_tries++, actual_tries++ + ) { + // clear interrupts + response_t result = dwhci_write_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), + 0xffffffff + ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + result = dwhci_write_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT_MASK( channel ), + 0 + ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + // fetch transfer size + uint32_t transfer_size; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ), &transfer_size ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + // fetch split control + uint32_t split_control; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ), &split_control ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + // transmit channel + result = dwhci_transmit_channel( channel, ( uint8_t* )buffer + buffer_offset ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + uint32_t timeout = 0; + do { + // handle timeout + if (timeout++ == 5000) { + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + return HCD_RESPONSE_ERROR_TIMEOUT; + } + + uint32_t interrupt; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), &interrupt ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + if ( interrupt & HCD_CHANNEL_INTERRUPT_HALT ) { + STARTUP_PRINT( "Halt interrupt: %#"PRIx32"!\r\n", interrupt ) + break; + } + + const long milliseconds = 1; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + } while( true ); + + result = dwhci_read_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ), + &transfer_size + ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + uint32_t interrupt; + result = dwhci_read_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), + &interrupt ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + if ( split_control & ( uint32_t)HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_SPLIT_ENABLE ) { + if ( interrupt & HCD_CHANNEL_INTERRUPT_ACKNOWLEDGEMENT ) { + for ( tries = 0; tries < 3; tries++ ) { + // clear interrupts + result = dwhci_write_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), + 0xffffffff + ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + result = dwhci_write_port( + ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT_MASK( channel ), + 0 + ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ), &split_control ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + // unset complete split + split_control &= ( uint32_t )~( HCD_DWHCI_CHAN_SPLIT_CONTROL_COMPLETE_SPLIT( true ) ); + // write back + result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ), split_control ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + // read characteristic + uint32_t characteristic; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ), &characteristic ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + // unset packets per frame, enable and disable + characteristic &= ( uint32_t )~( + ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ) + | ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_DISABLE( 1 ) + ); + // set packets per frame and enable + characteristic |= ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ); + // write back + result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ), characteristic ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + timeout = 0; + do { + // handle timeout + if (timeout++ == 5000) { + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + return HCD_RESPONSE_ERROR_TIMEOUT; + } + + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_INT( channel ), &interrupt ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + + if ( interrupt & HCD_CHANNEL_INTERRUPT_HALT ) { + break; + } + + const long milliseconds = 1; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + } while( true ); + + if ( ! ( interrupt & HCD_CHANNEL_INTERRUPT_NOT_YET ) ) { + break; + } + } + + if ( tries == 3 ) { + const long milliseconds = 25; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + continue; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_NEGATIVE_ACKNOWLEDGEMENT ) { + global_tries--; + const long milliseconds = 25; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + continue; + } + if ( interrupt & HCD_CHANNEL_INTERRUPT_TRANSACTION_ERROR ) { + const long milliseconds = 25; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + continue; + } + + result = dwhci_channel_interrupt_to_error( error, channel, false ); + if ( HCD_RESPONSE_OK != result ) { + return result; + } + } else if ( interrupt & HCD_CHANNEL_INTERRUPT_NEGATIVE_ACKNOWLEDGEMENT ) { + global_tries--; + const long milliseconds = 25; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + continue; + } else if ( interrupt & HCD_CHANNEL_INTERRUPT_TRANSACTION_ERROR ) { + const long milliseconds = 25; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + continue; + } + } else { + result = dwhci_channel_interrupt_to_error( + error, channel, !( split_control & ( uint32_t )HCD_DWHCI_CHAN_SPLIT_CONTROL_EXTRACT_SPLIT_ENABLE ) ); + if ( HCD_RESPONSE_OK != result ) { + return HCD_RESPONSE_RETRY; + } + } + + break; + } + + if ( global_tries == 3 || actual_tries == 10 ) { + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + return HCD_RESPONSE_ERROR_TIMEOUT; + } + + return HCD_RESPONSE_OK; +} + +response_t dwhci_prepare_channel( + const uint32_t parent_device_number, + const uint32_t port_number, + const uint8_t channel, + const uint32_t buffer_length, + const dwhci_channel_state_t packet_id, + libusb_pipe_address_t* pipe +) { + STARTUP_PRINT( "%d / %d / %"PRIu8" / %"PRIu8" / %d / %d\r\n", + pipe->max_size, pipe->speed, pipe->end_point, pipe->device, pipe->type, pipe->direction ) + // prepare characteristic + const uint32_t characteristic = HCD_DWHCI_CHAN_CHARACTER_DEVICE_ADDRESS( pipe->device ) + | HCD_DWHCI_CHAN_CHARACTER_END_POINT_NUMBER( pipe->end_point ) + | HCD_DWHCI_CHAN_CHARACTER_END_POINT_DIRECTION( pipe->direction ) + | HCD_DWHCI_CHAN_CHARACTER_LOW_SPEED( pipe->speed == LIBUSB_SPEED_LOW ? true : false ) + | HCD_DWHCI_CHAN_CHARACTER_TYPE( pipe->type ) + | HCD_DWHCI_CHAN_CHARACTER_MAXIMUM_PACKET_SIZE( usb_number_from_packet_size( pipe->max_size ) ) + | HCD_DWHCI_CHAN_CHARACTER_ENABLE( false ) + | HCD_DWHCI_CHAN_CHARACTER_DISABLE( false ); + // prepare split control + uint32_t split_control = 0; + if ( LIBUSB_SPEED_HIGH != pipe->speed ) { + split_control = ( uint32_t )HCD_DWHCI_CHAN_SPLIT_CONTROL_SPLIT_ENABLE( true ) + | HCD_DWHCI_CHAN_SPLIT_CONTROL_HUB_ADDRESS( parent_device_number ) + | HCD_DWHCI_CHAN_SPLIT_CONTROL_PORT_ADDRESS( port_number ); + } + // prepare transfer data + uint32_t transfer_data = + HCD_DWHCI_CHAN_XFER_SIZE_TRANSFER_SIZE( buffer_length ) + | HCD_DWHCI_CHAN_XFER_SIZE_PACKET_ID( packet_id ); + + uint32_t packet_count = ( buffer_length + 7 ) / 8; + STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", + characteristic, split_control, transfer_data, packet_count ) + if ( LIBUSB_SPEED_LOW != pipe->speed ) { + packet_count = ( + buffer_length + usb_number_from_packet_size( pipe->max_size ) - 1 ) / usb_number_from_packet_size( pipe->max_size ); + } + if ( 0 == packet_count ) { + packet_count = 1; + } + transfer_data |= HCD_DWHCI_CHAN_XFER_SIZE_PACKET_COUNT( packet_count ); + STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", + characteristic, split_control, transfer_data, packet_count ) + // allocate mmio sequence + size_t sequence_size; + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 3, &sequence_size ); + if ( ! sequence ) { + // debug output + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate sequence size\r\n" ) + #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // read split control with unset of complete split + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 0 ].value = characteristic; + // write back previous read to split control + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 1 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_SPLIT_CTRL( channel ); + sequence[ 1 ].value = split_control; + // set dma address + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 2 ].offset = ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ); + sequence[ 2 ].value = transfer_data; + // write to io + const int result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Transmit channel sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return io error + return HCD_RESPONSE_ERROR_IO; + } // free sequence free( sequence ); // return success return HCD_RESPONSE_OK; } +response_t dwhci_channel_send_wait( + const uint32_t parent_device_number, + const uint32_t port_number, + libusb_transfer_error_t* error, + libusb_pipe_address_t* pipe, + const uint8_t channel, + void* buffer, + const size_t buffer_length, + const dwhci_channel_state_t packet_id, + uint32_t* transfer_out +) { + uint32_t tries = 0; + uint32_t packets; + do { + // prepare channel + response_t result = dwhci_prepare_channel( parent_device_number, + port_number, channel, buffer_length, packet_id, pipe ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to prepare the channel\r\n" ) + #endif + // return result + return result; + } + size_t transferred = 0; + uint32_t transfer_data; + bool retry_error = false; + do { + // read port + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ), &transfer_data ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to read port data\r\n" ) + #endif + // return result + return result; + } + // set packets + packets = HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ); + // transfer + result = dwhci_channel_send_wait_one( error, channel, buffer, transferred, pipe->speed ); + // handle retry + if ( HCD_RESPONSE_RETRY == result ) { + retry_error = true; + break; + } + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to transfer data\r\n" ) + #endif + // return result + return result; + } + // read port + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ), &transfer_data ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to read port data\r\n" ) + #endif + // return result + return result; + } + STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, packets ); + transferred = buffer_length - HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_TRANSFER_SIZE( transfer_data ); + STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ); + if ( packets == HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ) { + break; + } + } while ( HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) > 0 ); + + // handle retry error + if ( retry_error ) { + continue; + } + + // read port + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CHAN_XFER_SIZE( channel ), &transfer_data ); + // handle error + if ( HCD_RESPONSE_OK != result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to read port data\r\n" ) + #endif + // return result + return result; + } + // handle stuck + if ( + packets == HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) + && buffer_length != 0 + ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Reading device got stuck %"PRIu32" / %"PRIu32"\r\n", + packets, HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ) + #endif + // return error + return HCD_RESPONSE_ERROR_UNKNOWN; + } + *transfer_out = HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_TRANSFER_SIZE( transfer_data ); + // return success + return HCD_RESPONSE_OK; + } while ( tries++ < 3 ); + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; +} + /** * @fn response_t dwhci_power_on(void) * @brief Method to power on usb device @@ -193,15 +857,23 @@ response_t dwhci_power_on( void ) { } /** - * @fn response_t dwhci_enable_global_interrupts( void ); - * @brief Wrapper to enable all interrupts + * @fn response_t dwhci_core_flush_tx_fifo(const uint32_t) + * @brief Wrapper to flush tx fifo + * @param num_fifo num fifo * @return + * + * @todo check whether loop is correct */ -response_t dwhci_enable_global_interrupts( void ) { +response_t dwhci_core_flush_tx_fifo( const uint32_t num_fifo ) { // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enabling all usb interrupts\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo %#"PRIx32"\r\n", num_fifo ) #endif + + // set initial reset fifo flush + const uint32_t reset = HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH + | ( num_fifo << HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT ); + // allocate sequence size_t sequence_size; iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); @@ -213,15 +885,19 @@ response_t dwhci_enable_global_interrupts( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read ahb config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - // mask all interrupts - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - sequence[ 1 ].value = HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK; + // write reset config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 0 ].value = reset; + // loop while it's there + sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH; + sequence[ 1 ].loop_max_iteration = 10; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 1; // perform request - const int result = ioctl( + const int ioctl_result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -231,30 +907,42 @@ response_t dwhci_enable_global_interrupts( void ) { sequence ); // handle ioctl error - if ( -1 == result ) { + if ( -1 == ioctl_result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable all interrupts failed\r\n" ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // free sequence + // check for timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // free sequence again free( sequence ); // return success return HCD_RESPONSE_OK; } /** - * @brief Method to disable global interrupts - * @return disable interrupt response + * @fn response_t dwhci_core_flush_rx_fifo(void) + * @brief Wrapper to flush rx fifo + * @return */ -response_t dwhci_disable_global_interrupts( void ) { +response_t dwhci_core_flush_rx_fifo( void ) { // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Disabling all usb interrupts\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing rx fifo\r\n" ) #endif // allocate sequence size_t sequence_size; @@ -267,15 +955,19 @@ response_t dwhci_disable_global_interrupts( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read ahb config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - // mask all interrupts - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK; + // write reset config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 0 ].value = HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; + // loop while it's there + sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; + sequence[ 1 ].loop_max_iteration = 10; + sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 1 ].sleep = 10; // perform request - const int result = ioctl( + const int ioctl_result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -285,96 +977,85 @@ response_t dwhci_disable_global_interrupts( void ) { sequence ); // handle ioctl error - if ( -1 == result ) { + if ( -1 == ioctl_result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Disable all interrupts failed\r\n" ) + STARTUP_PRINT( "Phy power reset failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // free sequence + // check for timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // free sequence again free( sequence ); // return success return HCD_RESPONSE_OK; } -/** - * @fn response_t dwhci_register_interrupt(void) - * @brief Method to register interrupt - * @return register response - */ -response_t dwhci_register_interrupt( void ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Try to acquire interrupt %d\r\n", ARM_IRQ_USB ) - #endif - // try to acquire usb interrupt - _syscall_interrupt_acquire( ARM_IRQ_USB ); - // handle error - if ( errno ) { +response_t dwhci_init2( void ) { + // open file descriptor for mmio actions + if ( -1 == ( fd_iomem = open( IOMEM_DEVICE_PATH, O_RDWR ) ) ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to acquire interrupt %d: %s\r\n", ARM_IRQ_USB, - strerror( errno ) ) + STARTUP_PRINT( "Unable to open device\r\n" ) #endif - // return io error + // return error response return HCD_RESPONSE_ERROR_IO; } - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_reset_device(void) - * @brief Reset dwhci device - * @return - */ -response_t dwhci_reset_device( void ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Reset device\r\n" ) - #endif - // allocate sequence + // allocate data buffer + databuffer = mmap( NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_BUS | MAP_DEVICE , -1, 0 ); + if ( MAP_FAILED == databuffer ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate data buffer\r\n" ) + #endif + // close file descriptor + close( fd_iomem ); + // return memory error + return HCD_RESPONSE_ERROR_MEMORY; + } + // query vendor and hardware information size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 5, &sequence_size ); + iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + STARTUP_PRINT( "Unable to prepare mmio_sequence\r\n" ) #endif - // return error + // close file descriptor + close( fd_iomem ); + // return memory error return HCD_RESPONSE_ERROR_MEMORY; } - // loop while ahb idle - sequence[ 0 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 0 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_AHB_IDLE; - sequence[ 0 ].loop_max_iteration = 10; - sequence[ 0 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 0 ].sleep = 10; - // read reset value + // prepare mmio sequence + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_VENDOR_ID; sequence[ 1 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - // core soft reset - sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; - sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 2 ].value = HCD_DWHCI_CORE_RESET_SOFT_RESET; - // wait until it's gone - sequence[ 3 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; - sequence[ 3 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 3 ].loop_and = HCD_DWHCI_CORE_RESET_SOFT_RESET; - sequence[ 3 ].loop_max_iteration = 10; - sequence[ 3 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 3 ].sleep = 10; - // delay 100 ms - sequence[ 4 ].type = IOMEM_MMIO_ACTION_SLEEP; - sequence[ 4 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 4 ].sleep = 100; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USER_ID; + sequence[ 2 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG1; + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG2; + sequence[ 4 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG3; + sequence[ 5 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 5 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG4; + sequence[ 6 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 6 ].offset = PERIPHERAL_DWHCI_HOST_CFG; // perform request - const int result = ioctl( + int result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -387,133 +1068,96 @@ response_t dwhci_reset_device( void ) { if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Reset sequence failed\r\n" ) + STARTUP_PRINT( "Querying vendor information failed\r\n" ) #endif + // close file descriptor + close( fd_iomem ); // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // check for first timeout - if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 0 ].abort_type ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Wait for idle timed out\r\n" ) - #endif - // free sequence - free( sequence ); - // return timeout - return HCD_RESPONSE_ERROR_TIMEOUT; - } - // check for second timeout - if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 3 ].abort_type ) { + // cache everything locally + const uint32_t vendor = sequence[ 0 ].value; + const uint32_t user = sequence[ 1 ].value; + const uint32_t hw_cfg1 = sequence[ 2 ].value; + const uint32_t hw_cfg2 = sequence[ 3 ].value; + const uint32_t hw_cfg3 = sequence[ 4 ].value; + const uint32_t hw_cfg4 = sequence[ 5 ].value; + uint32_t host_cfg = sequence[ 6 ].value; + // free sequence + free( sequence ); + // check fetched vendor + if ( ( vendor & 0xfffff000 ) != 0x4F542000 ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Wait for reset timed out\r\n" ) + STARTUP_PRINT( "HCD: Driver incompatible\r\n" ) #endif - // free sequence - free( sequence ); - // return timeout - return HCD_RESPONSE_ERROR_TIMEOUT; + // close fd_iomem again + close( fd_iomem ); + // return error + return HCD_RESPONSE_ERROR_INCOMPATIBLE; } - // free sequence again - free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_enable_common_interrupts(void) - * @brief Enable common interrupts - * @return - */ -response_t dwhci_enable_common_interrupts( void ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable common interrupts\r\n" ) + STARTUP_PRINT( + "HCD: Hardware: %c%c%"PRIx32".%"PRIx32"%"PRIx32"%"PRIx32" (BCM%.5"PRIx32")\r\n", + ( char )( vendor >> 24 & 0xff ), + ( char )( vendor >> 16 & 0xff ), + vendor >> 12 & 0xf, + vendor >> 8 & 0xf, + vendor >> 4 & 0xf, + vendor >> 0 & 0xf, + user >> 12 & 0xffff + ) + STARTUP_PRINT( "Hardware configuration: %#08"PRIx32" %#08"PRIx32" %#08"PRIx32" %#08"PRIx32"\r\n", + hw_cfg1, hw_cfg2, hw_cfg3, hw_cfg4 ) + STARTUP_PRINT( "Host configuration: %#08"PRIx32"\r\n", host_cfg ) #endif - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read interrupt stat - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_STAT; - // enable all interrupts - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_INT_STAT; - sequence[ 1 ].value = ( uint32_t )-1; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { + // check architecture + if ( HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE( hw_cfg2 ) != HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE_INTERNAL_DMA ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence failed\r\n" ) /// FIXME: PROVIDE SOME MEANINGFUL OUTPUT + STARTUP_PRINT( "Host architecture is not internal DMA\r\n" ) #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; + // close descriptor + close( fd_iomem ); + // return incompatible + return HCD_RESPONSE_ERROR_INCOMPATIBLE; } - // free sequence - free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_read_core_cfg2(uint32_t*) - * @brief Wrapper to read cfg2 - * @param cfg2 - * @return - */ -response_t dwhci_read_core_cfg2( uint32_t* cfg2 ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read cfg2\r\n" ) - #endif - // validate parameter - if ( ! cfg2 ) { + // check hs phy + /*if ( HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( hw_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_NOT_SUPPORTED ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "No pointer passed for result\r\n" ) + STARTUP_PRINT( "High speed physical not supported\r\n" ) #endif - // return error - return HCD_RESPONSE_ERROR_EINVAL; - } - - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + // close file descriptor + close( fd_iomem ); + // return incompatible + return HCD_RESPONSE_ERROR_INCOMPATIBLE; + }*/ + // disable interrupts + sequence = util_prepare_mmio_sequence( 3, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) + STARTUP_PRINT( "Unable to prepare mmio_sequence\r\n" ) #endif - // return error + // close file descriptor + close( fd_iomem ); + // return memory error return HCD_RESPONSE_ERROR_MEMORY; } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_HW_CFG2; + sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; + sequence[ 0 ].value = 0; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_INTERRUPT_MASK; + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE_PREVIOUS_READ; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; // perform request - const int ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -523,48 +1167,39 @@ response_t dwhci_read_core_cfg2( uint32_t* cfg2 ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + STARTUP_PRINT( "Disable of interrupts failed\r\n" ) #endif + // close file descriptor + close( fd_iomem ); // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // write back result - *cfg2 = sequence[ 0 ].value; // free sequence free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_read_core_cfg(uint32_t*) - * @brief Wrapper to read cfg - * @param cfg - * @return - */ -response_t dwhci_read_core_cfg( uint32_t* cfg ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read usb cfg\r\n" ) - #endif - // validate parameter - if ( ! cfg ) { + // power on usb hub + result = dwhci_power_on(); + // handle error + if ( 0 != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "No pointer passed for result\r\n" ) + STARTUP_PRINT( "Unable to power on hub\r\n" ) #endif + // close file descriptor + close( fd_iomem ); // return error - return HCD_RESPONSE_ERROR_EINVAL; + return HCD_RESPONSE_ERROR_IO; } - + // debug output + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Disable pulse and vbus and perform initial resetr\r\n" ) + #endif // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) @@ -573,11 +1208,40 @@ response_t dwhci_read_core_cfg( uint32_t* cfg ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + // read core usb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_ULPI_EXT_VBUS_DRV; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_TERM_SEL_DL_PULSE; + // loop while ahb idle + sequence[ 2 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 2 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_AHB_IDLE; + sequence[ 2 ].loop_max_iteration = 10; + sequence[ 2 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 2 ].sleep = 10; + // read reset value + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + // core soft reset + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 4 ].value = HCD_DWHCI_CORE_RESET_SOFT_RESET; + // wait until it's gone + sequence[ 5 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 5 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 5 ].loop_and = HCD_DWHCI_CORE_RESET_SOFT_RESET; + sequence[ 5 ].loop_max_iteration = 10; + sequence[ 5 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 5 ].sleep = 10; + // delay 100 ms + sequence[ 6 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 6 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 6 ].sleep = 100; // perform request - const int ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -587,38 +1251,47 @@ response_t dwhci_read_core_cfg( uint32_t* cfg ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + STARTUP_PRINT( "Reset sequence failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // write back result - *cfg = sequence[ 0 ].value; + // check for first timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 2 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for idle timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; + } + // check for second timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 5 ].abort_type ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Wait for reset timed out\r\n" ) + #endif + // free sequence + free( sequence ); + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; + } // free sequence free( sequence ); - // return success - return HCD_RESPONSE_OK; -} -/** - * @fn response_t dwhci_init_core(void) - * @brief Init dwhci core - * @return - */ -response_t dwhci_init_core( void ) { // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Init core\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Phy initialization with reset\r\n" ) #endif - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); + sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) @@ -630,12 +1303,37 @@ response_t dwhci_init_core( void ) { // read core usb config sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_ULPI_EXT_VBUS_DRV; - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_PHYIF; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_TERM_SEL_DL_PULSE; + sequence[ 1 ].value = HCD_DWHCI_CORE_USB_CFG_ULPI_UTMI_SEL; + // loop while ahb idle + sequence[ 2 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 2 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_AHB_IDLE; + sequence[ 2 ].loop_max_iteration = 10; + sequence[ 2 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 2 ].sleep = 10; + // read reset value + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + // core soft reset + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 4 ].value = HCD_DWHCI_CORE_RESET_SOFT_RESET; + // wait until it's gone + sequence[ 5 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 5 ].offset = PERIPHERAL_DWHCI_CORE_RESET; + sequence[ 5 ].loop_and = HCD_DWHCI_CORE_RESET_SOFT_RESET; + sequence[ 5 ].loop_max_iteration = 10; + sequence[ 5 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 5 ].sleep = 10; + // delay 100 ms + sequence[ 6 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 6 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 6 ].sleep = 100; // perform request - int ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -645,864 +1343,82 @@ response_t dwhci_init_core( void ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence failed\r\n" ) /// FIXME: PROVIDE SOME MEANINGFUL OUTPUT + STARTUP_PRINT( "Reset sequence failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // free sequence - free( sequence ); - - // reset dwhci device - response_t result = dwhci_reset_device(); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Reset device failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; - } - - // allocate sequence - sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read core usb config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_ULPI_UTMI_SEL; - // write prevoius read with logical and - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - // select utmi+ and utmi width of 8 - sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_PHYIF; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "select utmi+ and utmi width of 8 failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence - free( sequence ); - - uint32_t cfg2; - result = dwhci_read_core_cfg2( &cfg2 ); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of core cfg2 failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; - } - - // handle wrong architecture - if ( HCD_DWHCI_CORE_HW_CFG2_ARCHITECTURE( cfg2 ) != 2 ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unsupported architecture\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_INCOMPATIBLE; - } - - uint32_t cfg; - result = dwhci_read_core_cfg( &cfg ); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; - } - - // set configuration depending on cfg2 - if ( - HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI - && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED - ) { - #if defined ( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT("SET ULPI_FSLS AND CLK_SUS_M\r\n") - #endif - // enable configuration - cfg |= - HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M; - } - else { - #if defined ( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT("UNSET ULPI_FSLS AND CLK_SUS_M\r\n") - #endif - // disable configuration - cfg &= (uint32_t)~( - HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M ); - } - - // write back cfg - // allocate sequence - sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // write back cfg2 - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - sequence[ 0 ].value = cfg; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "write back of core usb cfg failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - - // read cfg2 again - result = dwhci_read_core_cfg2( &cfg2 ); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of core cfg2 failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; - } - - // validate number of channels - const uint32_t num_channel = HCD_DWHCI_CORE_HW_CFG2_NUM_HOST_CHANNELS( cfg2 ); - if ( ! ( 4 <= num_channel && num_channel <= PERIPHERAL_DWHCI_MAX_CHANNELS ) ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Invalid number of channels\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_INCOMPATIBLE; - } - - // read ahb cfg - // allocate sequence - sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "read of usb core failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // cache it in a variable - uint32_t ahb_cfg = sequence[ 0 ].value; - // free sequence - free( sequence ); - // manipulate config - ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; - ahb_cfg |= HCD_DWHCI_CORE_AHB_CFG_GLOBAL_WAIT_AXI_WRITES; - ahb_cfg &= ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_MAX_AXI_BURST_MASK; - // allocate sequence to write it back - sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; - sequence[ 0 ].value = ahb_cfg; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "write back of ahb config\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence - free( sequence ); - - // hnp and srp are not used - // allocate sequence - sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_USB_CFG; - sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE; - // write previous read with and - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; - sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "read of usb core failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence again - free( sequence ); - - // enable common interrupts - result = dwhci_enable_common_interrupts(); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "enable common interrupts failed: %s\r\n", - response_error( result ) ) - #endif - // return error - return result; - } - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_read_host_cfg(uint32_t*) - * @brief Wrapper to read cfg - * @param cfg - * @return - */ -response_t dwhci_read_host_cfg( uint32_t* cfg ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read usb host cfg\r\n" ) - #endif - // validate parameter - if ( ! cfg ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "No pointer passed for result\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_EINVAL; - } - - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CFG; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // write back result - *cfg = sequence[ 0 ].value; - // free sequence - free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_core_flush_tx_fifo(const uint32_t) - * @brief Wrapper to flush tx fifo - * @param num_fifo num fifo - * @return - * - * @todo check whether loop is correct - */ -response_t dwhci_core_flush_tx_fifo( const uint32_t num_fifo ) { - // debug output - #if defined ( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flushing tx fifo %#"PRIx32"\r\n", num_fifo ) - #endif - - // set initial reset fifo flush - uint32_t reset = 0; - reset |= HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH; - reset &= ( uint32_t )~HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_MASK; - reset |= num_fifo << HCD_DWHCI_CORE_RESET_TX_FIFO_NUM_SHIFT; - - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // write reset config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 0 ].value = reset; - // loop while it's there - sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_TX_FIFO_FLUSH; - sequence[ 1 ].loop_max_iteration = 10; - sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 1 ].sleep = 1; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Phy power reset failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // check for timeout - if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_TIMEOUT; - } - // free sequence again - free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_core_flush_rx_fifo(void) - * @brief Wrapper to flush rx fifo - * @return - */ -response_t dwhci_core_flush_rx_fifo( void ) { - // debug output - #if defined ( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flushing rx fifo\r\n" ) - #endif - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // write reset config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 0 ].value = HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; - // loop while it's there - sequence[ 1 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_RESET; - sequence[ 1 ].loop_and = ( uint32_t )HCD_DWHCI_CORE_RESET_RX_FIFO_FLUSH; - sequence[ 1 ].loop_max_iteration = 10; - sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 1 ].sleep = 10; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Phy power reset failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // check for timeout - if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 1 ].abort_type ) { + // check for first timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 2 ].abort_type ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flushing tx fifo timed out\r\n" ) + STARTUP_PRINT( "Wait for idle timed out\r\n" ) #endif // free sequence free( sequence ); - // return error + // return timeout return HCD_RESPONSE_ERROR_TIMEOUT; } - // free sequence again - free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_write_host_port(uint32_t) - * @brief Helper to write back host port value - * @param port - * @return - */ -response_t dwhci_write_host_port( const uint32_t port ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Writing host port value %#"PRIx32"\r\n", port ) - #endif - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 1 ].value = port; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence - free( sequence ); - // return success - return HCD_RESPONSE_OK; - -} - -/** - * @fn response_t dwhci_read_host_cfg(uint32_t*) - * @brief Wrapper to read cfg - * @param port - * @return - */ -response_t dwhci_read_host_port( uint32_t* port ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read host port\r\n" ) - #endif - // validate parameter - if ( ! port ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "No pointer passed for result\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_EINVAL; - } - - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - // perform request - const int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { + // check for second timeout + if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 5 ].abort_type ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) + STARTUP_PRINT( "Wait for reset timed out\r\n" ) #endif // free sequence free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; + // return timeout + return HCD_RESPONSE_ERROR_TIMEOUT; } - // write back result - *port = sequence[ 0 ].value; // free sequence free( sequence ); - // return success - return HCD_RESPONSE_OK; -} -/** - * @fn response_t dwhci_enable_host_interrupts(void); - * @brief Wrapper to enable host interrupts - * @return - */ -response_t dwhci_enable_host_interrupts( void ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable host interrupts\r\n" ) + STARTUP_PRINT( "Preparing usb configuration\r\n" ) #endif - - // reset core interrupts - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; - sequence[ 0 ].value = 0; - // perform request - int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of hw cfg2 failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence - free( sequence ); - - // enable common interrupts again - const response_t result = dwhci_enable_common_interrupts(); - // handle error + // query standalone register + uint32_t usb_cfg; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_CORE_USB_CFG, &usb_cfg ); if ( HCD_RESPONSE_OK != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable host interrupts failed: %s\r\n", response_error( result ) ) + STARTUP_PRINT( "Read port failed\r\n" ) #endif - // return result return result; } - - // read core interrupts again and enable host interrupts - // allocate sequence - sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; - // write with or previous read - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_INT_MASK; - sequence[ 1 ].value = HCD_DWHCI_CORE_INT_MASK_HC_INTR; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable of host interrupts failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence - free( sequence ); - - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_init_host(void) - * @brief Init dwhci host - * @return - */ -response_t dwhci_init_host( void ) { - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Initialize host\r\n" ) - #endif - // set phy power - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 1, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_USB_POWER_OFFSET; - sequence[ 0 ].value = 0; - // perform request - int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Phy power reset failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // free sequence again - free( sequence ); - - // read out host config - uint32_t host_cfg; - response_t result = dwhci_read_host_cfg( &host_cfg ); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of host cfg failed: %s\r\n", response_error( result ) ) - #endif - // return error - return result; + if ( + HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( hw_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI + && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( hw_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED + ) { + // enable configuration + usb_cfg |= HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M; } - host_cfg &= ( uint32_t )~HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_MASK; - - // read core cfg - uint32_t core_cfg2; - result = dwhci_read_core_cfg2( &core_cfg2 ); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; + else { + // disable configuration + usb_cfg &= (uint32_t)~( HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS | HCD_DWHCI_CORE_USB_CFG_ULPI_CLK_SUS_M ); } - - // read core cfg - uint32_t core_cfg; - result = dwhci_read_core_cfg( &core_cfg ); + // write back value + result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_CORE_USB_CFG, usb_cfg ); if ( HCD_RESPONSE_OK != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read of core cfg failed: %s\r\n", response_error( result ) ) + STARTUP_PRINT( "Write port failed\r\n" ) #endif - // return result return result; } - // adjust host config - if ( - HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI - && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( core_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED - && HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS & core_cfg - ) { - host_cfg |= HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ; - } else { - host_cfg |= HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_30_60_MHZ; - } - - // write back host config - // allocate sequence - sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Preparing dma configuration\r\n" ) + #endif + // prepare sequence + sequence = util_prepare_mmio_sequence( 2, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) @@ -1511,12 +1427,15 @@ response_t dwhci_init_host( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CFG; - sequence[ 0 ].value = host_cfg; + // read core usb config + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 0 ].value = ( uint32_t )~HCD_DWHCI_CORE_AHB_CFG_GLOBAL_AHB_SINGLE; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_AHB_CFG; + sequence[ 1 ].value = HCD_DWHCI_CORE_AHB_CFG_GLOBAL_DMA_ENABLE; // perform request - ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -1526,22 +1445,59 @@ response_t dwhci_init_host( void ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Set host config failed\r\n" ) + STARTUP_PRINT( "Reset sequence failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // free sequence again free( sequence ); - // write rx fifo size, non-periodic tx fifo size and host periodic fifo size - // allocate sequence - sequence = util_prepare_mmio_sequence( 3, &sequence_size ); + // query usb port again + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_CORE_USB_CFG, &usb_cfg ); + if ( HCD_RESPONSE_OK != result ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Read port failed\r\n" ) + #endif + return result; + } + switch ( HCD_DWHCI_CORE_HW_CFG2_OP_MODE( hw_cfg2 ) ) { + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_HNP_SRP_CAPABLE: + usb_cfg |= HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE | HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE; + break; + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_ONLY_CAPABLE: + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_SRP_CAPABLE_HOST: + usb_cfg &= (uint32_t)~HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE; + usb_cfg |= HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE; + break; + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_HNP_SRP_CAPABLE: + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE: + case HCD_DWHCI_CORE_HW_CFG2_OP_MODE_NO_SRP_CAPABLE_HOST: + default: + usb_cfg &= (uint32_t)~HCD_DWHCI_CORE_USB_CFG_HNP_CAPABLE; + usb_cfg &= (uint32_t)~HCD_DWHCI_CORE_USB_CFG_SRP_CAPABLE; + break; + } + result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_CORE_USB_CFG, usb_cfg ); + if ( HCD_RESPONSE_OK != result ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Write port failed\r\n" ) + #endif + return result; + } + + + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Preparing host startup\r\n" ) + #endif + // prepare sequence + sequence = util_prepare_mmio_sequence( 10, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) @@ -1550,22 +1506,47 @@ response_t dwhci_init_host( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // write rx fifo size + // power down sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_CORE_RX_FIFO_SIZ; - sequence[ 0 ].value = HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE; - // write non-periodic tx fifo size - sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 1 ].offset = PERIPHERAL_DWHCI_CORE_NPER_FIFO_SIZ; - sequence[ 1 ].value = HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE | - ( HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE << 16 ); - // write host periodic fifo size - sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 2 ].offset = PERIPHERAL_DWHCI_CORE_HOST_PER_TX_FIFO_SZ; - sequence[ 2 ].value = ( HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE + HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE ) + sequence[ 0 ].offset = PERIPHERAL_USB_POWER_OFFSET; + sequence[ 0 ].value = 0; + // set clock rate + sequence[ 1 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + sequence[ 1 ].value = ( uint32_t )~HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_MASK; + sequence[ 2 ].type = IOMEM_MMIO_ACTION_WRITE_PREVIOUS_READ; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + sequence[ 2 ].value = HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE( hw_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_HS_PHY_TYPE_ULPI + && HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE( hw_cfg2 ) == HCD_DWHCI_CORE_HW_CFG2_FS_PHY_TYPE_DEDICATED + && usb_cfg & HCD_DWHCI_CORE_USB_CFG_ULPI_FSLS + ? HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_48_MHZ + : HCD_DWHCI_HOST_CFG_FSLS_PCLK_SEL_30_60_MHZ; + // enable fsls only + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_HOST_CFG; + sequence[ 4 ].value = HCD_DWHCI_HOST_CFG_FSLS_ONLY; + // write fifo size + sequence[ 5 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 5 ].offset = PERIPHERAL_DWHCI_CORE_RX_FIFO_SIZ; + sequence[ 5 ].value = PERIPHERAL_DWHCI_DATA_FIFO_SIZE; + // write nper fifo size + sequence[ 6 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 6 ].offset = PERIPHERAL_DWHCI_CORE_NPER_FIFO_SIZ; + sequence[ 6 ].value = HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE | ( HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE << 16 );; + sequence[ 7 ].type = IOMEM_MMIO_ACTION_WRITE; + sequence[ 7 ].offset = PERIPHERAL_DWHCI_CORE_HOST_PER_TX_FIFO_SZ; + sequence[ 7 ].value = ( HCD_DWHCI_CFG_HOST_RX_FIFO_SIZE + HCD_DWHCI_CFG_HOST_NPER_TX_FIFO_SIZE ) | HCD_DWHCI_CFG_HOST_PER_TX_FIFO_SIZE << 16; + // enable otg + sequence[ 8 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 8 ].offset = PERIPHERAL_DWHCI_CORE_CTRL; + sequence[ 9 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 9 ].offset = PERIPHERAL_DWHCI_CORE_CTRL; + sequence[ 9 ].value = HCD_DWHCI_CORE_CTRL_HOST_SET_NP_ENABLE; // perform request - ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -1575,64 +1556,51 @@ response_t dwhci_init_host( void ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Phy power reset failed\r\n" ) + STARTUP_PRINT( "host config sequence failed\r\n" ) #endif // free sequence free( sequence ); // return error return HCD_RESPONSE_ERROR_IO; } - // free sequence again free( sequence ); - // flush rx fifo - result = dwhci_core_flush_tx_fifo( 0x10 ); - // handle error + result = dwhci_core_flush_tx_fifo( 16 ); if ( HCD_RESPONSE_OK != result ) { // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flush tx fifo failed: %s\r\n", response_error( result ) ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Flushing tx fifo failed\r\n" ) #endif - // return result return result; } - // flush tx fifo result = dwhci_core_flush_rx_fifo(); - // handle error if ( HCD_RESPONSE_OK != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Flush rx fifo failed: %s\r\n", response_error( result ) ) + STARTUP_PRINT( "Flushing rx fifo failed\r\n" ) #endif - // return result return result; } - // read port - uint32_t port; - result = dwhci_read_host_port( &port ); - // handle error + + // read out host config + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_CFG, &host_cfg ); if ( HCD_RESPONSE_OK != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read host port failed: %s\r\n", response_error( result ) ) + STARTUP_PRINT( "Read of host cfg failed: %s\r\n", response_error( result ) ) #endif - // return result + // return error return result; } - // mask port result - port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; - // set power if not set - if ( ! ( port & HCD_DWHCI_HOST_PORT_POWER ) ) { - // set flag - port |= HCD_DWHCI_HOST_PORT_POWER; - // write port back - // allocate sequence - sequence = util_prepare_mmio_sequence( 1, &sequence_size ); + // put channels into known states + if ( host_cfg & HCD_DWHCI_HOST_CFG_ENABLE_DMA_DESCRIPTOR ) { + // prepare sequence + sequence = util_prepare_mmio_sequence( 2, &sequence_size ); if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) @@ -1641,136 +1609,133 @@ response_t dwhci_init_host( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 0 ].value = port; - // perform request - ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { + // extract channel count + const uint32_t channel_count = HCD_DWHCI_CORE_HW_CFG2_NUM_HOST_CHANNELS( hw_cfg2 ); + // loop over channels + for ( uint32_t channel = 0; channel < channel_count; ++channel ) { + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_AND; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 0 ].value = ( uint32_t )~( + HCD_DWHCI_CHAN_CHARACTER_END_POINT_DIRECTION( 1 ) + | HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ) + | HCD_DWHCI_CHAN_CHARACTER_DISABLE( 1 ) + ); + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 1 ].value = HCD_DWHCI_CHAN_CHARACTER_DISABLE( 1 ) + | HCD_DWHCI_CHAN_CHARACTER_END_POINT_DIRECTION( 1 ); + // perform request + result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "host config sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + } + // free sequence again + free( sequence ); + // prepare sequence + sequence = util_prepare_mmio_sequence( 3, &sequence_size ); + if ( ! sequence ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Write back of host port failed\r\n" ) + STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) #endif + // return error + return HCD_RESPONSE_ERROR_MEMORY; + } + // loop through channels again + for ( uint32_t channel = 0; channel < channel_count; ++channel ) { + // read channel + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ; + sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + // set enable disable and end point direction + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 1 ].value = HCD_DWHCI_CHAN_CHARACTER_DISABLE( 1 ) + | ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ) + | HCD_DWHCI_CHAN_CHARACTER_END_POINT_DIRECTION( 1 ); + // wait until enable is gone + sequence[ 2 ].type = IOMEM_MMIO_ACTION_LOOP_TRUE; + sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_CHAN_CHARACTER( channel ); + sequence[ 2 ].loop_and = ( uint32_t )HCD_DWHCI_CHAN_CHARACTER_ENABLE( 1 ); + sequence[ 2 ].loop_max_iteration = 10; + sequence[ 2 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 2 ].sleep = 10; + // perform request + result = ioctl( + fd_iomem, + IOCTL_BUILD_REQUEST( + IOMEM_RPC_MMIO_PERFORM, + sequence_size, + IOCTL_RDWR + ), + sequence + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "host config sequence failed\r\n" ) + #endif + // free sequence + free( sequence ); + // return error + return HCD_RESPONSE_ERROR_IO; + } + // check for timeout + if ( sequence[ 2 ].abort_type == IOMEM_MMIO_ABORT_TYPE_TIMEOUT ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to clear halt on channel %"PRIu32"\r\n", + channel ) + #endif + } // free sequence free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; } - // free sequence again - free( sequence ); } - // enable host interrupts - result = dwhci_enable_host_interrupts(); - // handle error + uint32_t host_port; + result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable host interrupt failed: %s\r\n", response_error( result ) ) + STARTUP_PRINT( "host port read failed\r\n" ) #endif - // return result return result; } - - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_enable_root_port(void) - * @brief Wrapper to enable root port - * @return - */ -response_t dwhci_enable_root_port( void ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable root port\r\n" ) - #endif - - // allocate sequence - size_t sequence_size; - iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 2, &sequence_size ); - if ( ! sequence ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Sequence memory allocation failed\r\n" ) - #endif - // return error - return HCD_RESPONSE_ERROR_MEMORY; - } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_LOOP_FALSE; - sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 0 ].loop_and = ( uint32_t )HCD_DWHCI_HOST_PORT_CONNECT; - sequence[ 0 ].loop_max_iteration = 10; - sequence[ 0 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 0 ].sleep = 10; - // wait a bit - sequence[ 1 ].type = IOMEM_MMIO_ACTION_SLEEP; - sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 1 ].sleep = 100; - // perform request - int ioctl_result = ioctl( - fd_iomem, - IOCTL_BUILD_REQUEST( - IOMEM_RPC_MMIO_PERFORM, - sequence_size, - IOCTL_RDWR - ), - sequence - ); - // handle ioctl error - if ( -1 == ioctl_result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Wait for host port command sequence failed\r\n" ) - #endif - // free sequence - free( sequence ); - // return error - return HCD_RESPONSE_ERROR_IO; - } - // check for valid timeout - if ( IOMEM_MMIO_ABORT_TYPE_TIMEOUT == sequence[ 0 ].abort_type ) { - // debug output + if ( ! ( host_port & HCD_DWHCI_HOST_PORT_POWER ) ) { #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Wait for host port connect timed out, not really an error\r\n" ) + STARTUP_PRINT( "Power up host port\r\n" ) #endif - // free sequence - free( sequence ); - // return success - return HCD_RESPONSE_OK; + host_port |= HCD_DWHCI_HOST_PORT_POWER; + result = dwhci_write_port( PERIPHERAL_DWHCI_HOST_PORT, host_port ); + if ( HCD_RESPONSE_OK != result ) { + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "host port write failed\r\n" ) + #endif + return result; + } } - // free sequence again - free( sequence ); - // read host port - uint32_t host_port; - const response_t result = dwhci_read_host_port( &host_port ); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Read host port failed: %s\r\n", response_error( result ) ) - #endif - // return result - return result; - } - // mask host port and set reset - host_port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; - host_port |= HCD_DWHCI_HOST_PORT_RESET; - // write back value with delay and another write of host port - // allocate sequence + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Resetting host port\r\n" ) + #endif + // prepare sequence sequence = util_prepare_mmio_sequence( 5, &sequence_size ); if ( ! sequence ) { // debug output @@ -1780,28 +1745,26 @@ response_t dwhci_enable_root_port( void ) { // return error return HCD_RESPONSE_ERROR_MEMORY; } - // read config - sequence[ 0 ].type = IOMEM_MMIO_ACTION_WRITE; + // set host port reset flag and write it back + sequence[ 0 ].type = IOMEM_MMIO_ACTION_READ_OR; sequence[ 0 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 0 ].value = host_port; - // wait a bit - sequence[ 1 ].type = IOMEM_MMIO_ACTION_SLEEP; - sequence[ 1 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 1 ].sleep = 50; - // read host port - sequence[ 2 ].type = IOMEM_MMIO_ACTION_READ_AND; - sequence[ 2 ].offset = PERIPHERAL_DWHCI_HOST_PORT; - sequence[ 2 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_DEFAULT_MASK; - // write back with and - sequence[ 3 ].type = IOMEM_MMIO_ACTION_WRITE_AND_PREVIOUS_READ; + sequence[ 0 ].value = HCD_DWHCI_HOST_PORT_RESET; + sequence[ 1 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 1 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 1 ].value = 0x100; + // delay 100 ms + sequence[ 2 ].type = IOMEM_MMIO_ACTION_SLEEP; + sequence[ 2 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; + sequence[ 2 ].sleep = 100; + // reset reset flag + sequence[ 3 ].type = IOMEM_MMIO_ACTION_READ_AND; sequence[ 3 ].offset = PERIPHERAL_DWHCI_HOST_PORT; sequence[ 3 ].value = ( uint32_t )~HCD_DWHCI_HOST_PORT_RESET; - // wait a bit - sequence[ 4 ].type = IOMEM_MMIO_ACTION_SLEEP; - sequence[ 4 ].sleep_type = IOMEM_MMIO_SLEEP_MILLISECONDS; - sequence[ 4 ].sleep = 20; + sequence[ 4 ].type = IOMEM_MMIO_ACTION_WRITE_OR_PREVIOUS_READ; + sequence[ 4 ].offset = PERIPHERAL_DWHCI_HOST_PORT; + sequence[ 4 ].value = 0x100; // perform request - ioctl_result = ioctl( + result = ioctl( fd_iomem, IOCTL_BUILD_REQUEST( IOMEM_RPC_MMIO_PERFORM, @@ -1811,10 +1774,10 @@ response_t dwhci_enable_root_port( void ) { sequence ); // handle ioctl error - if ( -1 == ioctl_result ) { + if ( -1 == result ) { // debug output #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Write back of host port failed\r\n" ) + STARTUP_PRINT( "host config sequence failed: %s\r\n", strerror( errno ) ) #endif // free sequence free( sequence ); @@ -1823,166 +1786,6 @@ response_t dwhci_enable_root_port( void ) { } // free sequence free( sequence ); - // return success - return HCD_RESPONSE_OK; -} - -/** - * @fn response_t dwhci_init(void) - * @brief Init dwhci - * @return init response - */ -response_t dwhci_init( void ) { - // open file descriptor for mmio actions - if ( -1 == ( fd_iomem = open( IOMEM_DEVICE_PATH, O_RDWR ) ) ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to open device\r\n" ) - #endif - // return error response - return HCD_RESPONSE_ERROR_IO; - } - - // query vendor id - uint32_t vendor; - response_t result = dwhci_query_vendor( &vendor ); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Query vendor information failed: %s\r\n", response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( - "HCD: Hardware: %c%c%"PRIx32".%"PRIx32"%"PRIx32"%"PRIx32"\r\n", - ( char )( vendor >> 24 & 0xff ), - ( char )( vendor >> 16 & 0xff ), - vendor >> 12 & 0xf, - vendor >> 8 & 0xf, - vendor >> 4 & 0xf, - vendor >> 0 & 0xf ) - #endif - // check fetched vendor - if ( ( vendor & 0xfffff000 ) != 0x4F542000 ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "HCD: Driver incompatible\r\n" ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return error - return HCD_RESPONSE_ERROR_INCOMPATIBLE; - } - - // power on usb device - result = dwhci_power_on(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to power on usb device: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // disable global interrupts - result = dwhci_disable_global_interrupts(); - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to disable global interrupt: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // register interrupt handler - result = dwhci_register_interrupt(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to register interrupt: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // init core - result = dwhci_init_core(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to initialize core: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // enable global interrupts - result = dwhci_enable_global_interrupts(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to enable global interrupt: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // init core - result = dwhci_init_host(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to initialize host: %s\r\n", - response_error( result ) ) - #endif - // close fd_iomem again - close( fd_iomem ); - // return result - return result; - } - - // enable root port - result = dwhci_enable_root_port(); - // handle error - if ( HCD_RESPONSE_OK != result ) { - // debug output - #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Enable root port failed: %s\r\n", response_error( result ) ) - #endif - // close fd iomem - close( fd_iomem ); - // return result - return result; - } - - // return success + // return success, we're done return HCD_RESPONSE_OK; } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index e91b5066..8846e4ab 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -27,6 +27,7 @@ #define DWHCI_ENABLE_DEBUG 1 extern int fd_iomem; +extern void* databuffer; typedef enum { DWHCI_CHANNEL_STATE_DATA0 = 0, @@ -36,9 +37,13 @@ typedef enum { DWHCI_CHANNEL_STATE_SETUP = 3, } dwhci_channel_state_t; -response_t dwhci_prepare_channel( libusb_device_t*, uint8_t, uint32_t, dwhci_channel_state_t, libusb_pipe_address_t* ); -response_t dwhci_channel_send_wait_one( libusb_device_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, uint32_t, libusb_device_request_t* ); -response_t dwhci_channel_send_wait( libusb_device_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, libusb_device_request_t*, dwhci_channel_state_t ); +response_t dwhci_channel_interrupt_to_error( libusb_transfer_error_t*, uint8_t, bool ); +response_t dwhci_transmit_channel( uint8_t, void* ); +response_t dwhci_prepare_channel( uint32_t, uint32_t, uint8_t, uint32_t, dwhci_channel_state_t, libusb_pipe_address_t* ); +response_t dwhci_channel_send_wait_one( libusb_transfer_error_t*, uint8_t, void*, uint32_t, libusb_speed_t ); +response_t dwhci_channel_send_wait( uint32_t, uint32_t, libusb_transfer_error_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, dwhci_channel_state_t, uint32_t* ); +response_t dwhci_read_port( uint32_t, uint32_t* ); +response_t dwhci_write_port( uint32_t, uint32_t ); response_t dwhci_query_vendor( uint32_t* destination ); response_t dwhci_power_on( void ); @@ -47,10 +52,7 @@ response_t dwhci_disable_global_interrupts( void ); response_t dwhci_register_interrupt( void ); response_t dwhci_reset_device( void ); response_t dwhci_enable_common_interrupts( void ); -response_t dwhci_read_core_cfg2( uint32_t* ); -response_t dwhci_read_core_cfg( uint32_t* ); response_t dwhci_init_core( void ); -response_t dwhci_read_host_cfg( uint32_t* ); response_t dwhci_core_flush_tx_fifo( uint32_t ); response_t dwhci_core_flush_rx_fifo( void ); response_t dwhci_write_host_port( uint32_t ); @@ -59,5 +61,6 @@ response_t dwhci_enable_host_interrupts( void ); response_t dwhci_init_host( void ); response_t dwhci_enable_root_port( void ); response_t dwhci_init( void ); +response_t dwhci_init2( void ); #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c index f3200447..e1070bc1 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c @@ -138,9 +138,9 @@ static libusb_hub_descriptor_t hub_descriptor = { #pragma GCC diagnostic pop /** - * @fn int dwhciroothub_process(libusb_device_t*, libusb_pipe_address_t, void*, size_t, libusb_device_request_t*) + * @fn int dwhciroothub_process(libusb_transfer_error_t*, uint32_t, libusb_pipe_address_t, void*, size_t, libusb_device_request_t*) * @brief Process root hub request - * @param dev + * @param error * @param pipe * @param buffer * @param buffer_length @@ -148,14 +148,15 @@ static libusb_hub_descriptor_t hub_descriptor = { * @return */ int dwhciroothub_process( - libusb_device_t* dev, + libusb_transfer_error_t* error, + uint32_t* last_transfer, const libusb_pipe_address_t pipe, void* buffer, const size_t buffer_length, libusb_device_request_t* request ) { // set device to processing - dev->error = LIBUSB_TRANSFER_ERROR_PROCESSING; + *error = LIBUSB_TRANSFER_ERROR_PROCESSING; // check for interrupt pipe on root hub => not supported if ( LIBUSB_TRANSFER_INTERRUPT == pipe.type ) { // debug output @@ -163,7 +164,7 @@ int dwhciroothub_process( STARTUP_PRINT( "Root hub does not support irq pipes\r\n" ) #endif // set error - dev->error = LIBUSB_TRANSFER_ERROR_STALL; + *error = LIBUSB_TRANSFER_ERROR_STALL; // return success return 0; } @@ -203,9 +204,9 @@ int dwhciroothub_process( break; case 0xa3: // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } STARTUP_PRINT( "host_port = %"PRIx32"\r\n", host_port ) @@ -240,7 +241,7 @@ int dwhciroothub_process( reply_length = 4; break; default: - dev->error = LIBUSB_TRANSFER_ERROR_STALL; + *error = LIBUSB_TRANSFER_ERROR_STALL; } break; case LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE: @@ -254,17 +255,17 @@ int dwhciroothub_process( case LIBUSB_HUB_PORT_FEATURE_ENABLE: STARTUP_PRINT( "roothub port feature enable!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // set enable host_port |= HCD_DWHCI_HOST_PORT_ENABLE; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x4 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x4 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; @@ -273,7 +274,7 @@ int dwhciroothub_process( // allocate sequence sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { - dev->error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; + *error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; break; } // prepare sequence @@ -320,75 +321,75 @@ int dwhciroothub_process( free( sequence ); // handle ioctl error if ( -1 == ioctl_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_POWER: STARTUP_PRINT( "roothub port feature power!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // reset power bit host_port &= ( uint32_t )~HCD_DWHCI_HOST_PORT_POWER; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x1000 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x1000 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE: STARTUP_PRINT( "roothub port feature connection change!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // set connect changed host_port |= HCD_DWHCI_HOST_PORT_CONNECT_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x2 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x2 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE: STARTUP_PRINT( "roothub port feature enable change!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // set enable changed host_port |= HCD_DWHCI_HOST_PORT_ENABLE_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x8 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x8 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE: STARTUP_PRINT( "roothub port feature over current change!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // set over current changed host_port |= HCD_DWHCI_HOST_PORT_OVERCURRENT_CHANGED; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x20 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x20 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; @@ -410,7 +411,7 @@ int dwhciroothub_process( // allocate sequence sequence = util_prepare_mmio_sequence( 8, &sequence_size ); if ( ! sequence ) { - dev->error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; + *error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; break; } // read power with and @@ -459,24 +460,24 @@ int dwhciroothub_process( free( sequence ); // handle ioctl error if ( -1 == ioctl_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; case LIBUSB_HUB_PORT_FEATURE_POWER: STARTUP_PRINT( "roothub port feature power!\r\n" ) // read host port - dwhci_result = dwhci_read_host_port( &host_port ); + dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } // set over current changed host_port |= HCD_DWHCI_HOST_PORT_POWER; // write back host port - dwhci_result = dwhci_write_host_port( host_port | 0x1000 ); + dwhci_result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, host_port | 0x1000 ); if ( HCD_RESPONSE_OK != dwhci_result ) { - dev->error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; + *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } break; @@ -541,12 +542,12 @@ int dwhciroothub_process( } // handle invalid argument if ( EINVAL == result ) { - dev->error |= LIBUSB_TRANSFER_ERROR_STALL; + *error |= LIBUSB_TRANSFER_ERROR_STALL; } // strip out processing error - dev->error &= ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING; + *error &= ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING; // set last transfer - dev->last_transfer = reply_length; + *last_transfer = reply_length; // return success return 0; } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h index f0f42ffe..b46e851e 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.h @@ -25,6 +25,6 @@ extern uint32_t dwhciroothub_root_hub_device_number; -int dwhciroothub_process( libusb_device_t*, libusb_pipe_address_t, void*, size_t, libusb_device_request_t* ); +int dwhciroothub_process( libusb_transfer_error_t*, uint32_t*, libusb_pipe_address_t, void*, size_t, libusb_device_request_t* ); #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index 22eb8e2c..95fb9cd7 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -46,7 +46,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // setup hcd interface STARTUP_PRINT( "Setup hcd interface!\r\n" ) - const response_t result = dwhci_init(); + const response_t result = dwhci_init2(); if ( HCD_RESPONSE_OK != result ) { STARTUP_PRINT( "Unable to init dwhci: %s\r\n", response_error( result ) ); return -1; diff --git a/bolthur/server/platform/raspi/usb/hcd/response.c b/bolthur/server/platform/raspi/usb/hcd/response.c index 9cf30aa9..13383943 100644 --- a/bolthur/server/platform/raspi/usb/hcd/response.c +++ b/bolthur/server/platform/raspi/usb/hcd/response.c @@ -30,6 +30,7 @@ static response_message_entry_t response_error_message[] = { { "Timeout while waiting for completion" }, { "Unknown error" }, { "Driver incompatible" }, + { "Retry operation" }, }; /** diff --git a/bolthur/server/platform/raspi/usb/hcd/response.h b/bolthur/server/platform/raspi/usb/hcd/response.h index 3a899896..d7008363 100644 --- a/bolthur/server/platform/raspi/usb/hcd/response.h +++ b/bolthur/server/platform/raspi/usb/hcd/response.h @@ -30,6 +30,7 @@ typedef enum{ HCD_RESPONSE_ERROR_TIMEOUT, HCD_RESPONSE_ERROR_UNKNOWN, HCD_RESPONSE_ERROR_INCOMPATIBLE, + HCD_RESPONSE_RETRY, } response_t; typedef struct { diff --git a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c index b8b3a71c..ed23b420 100644 --- a/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c +++ b/bolthur/server/platform/raspi/usb/hcd/rpc/submit_control_message.c @@ -23,6 +23,8 @@ #include "../rpc.h" #include "../dwhci.h" #include "../dwhciroothub.h" +#include "../../../libhcd.h" +#include "../../../libperipheral.h" #include "../../../../../libhcd.h" /** @@ -92,7 +94,8 @@ void rpc_submit_control_message( if ( dwhciroothub_root_hub_device_number == message->pipe_address.device ) { // try to process root hub const int result = dwhciroothub_process( - &message->device, + &message->error, + &message->last_transfer, message->pipe_address, message->buffer, message->buffer_length, @@ -112,17 +115,141 @@ void rpc_submit_control_message( return; } } else { - STARTUP_PRINT( "PERFORM MESSAGE!\r\n" ) - // set error - error.status = -ENOSYS; - // detach shared memory - _syscall_memory_shared_detach( submit_control_message->shm_id ); - // free request - free( request ); - free( response ); - // return from rpc - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; + // setup device error and last transfer + message->error = LIBUSB_TRANSFER_ERROR_PROCESSING; + message->last_transfer = 0; + // create temporary pipe + libusb_pipe_address_t temporary_pipe = { + .speed = message->pipe_address.speed, + .device = message->pipe_address.device, + .end_point = message->pipe_address.end_point, + .max_size = message->pipe_address.max_size, + .type = LIBUSB_TRANSFER_CONTROL, + .direction = LIBUSB_DIRECTION_OUT, + }; + uint32_t transferred = 0; + // push request into data buffer + memcpy( databuffer, &message->request, sizeof( libusb_device_request_t ) ); + // setup channel + int result = dwhci_channel_send_wait( + message->parent_device_number, + message->port_number, + &message->error, + &temporary_pipe, + 0, + databuffer, + sizeof( libusb_device_request_t ), + DWHCI_CHANNEL_STATE_SETUP, + &transferred + ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Setup failed with %s\r\n", response_error( result ) ) + // set error + error.status = -result; + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + + // handle data + if ( message->buffer_length ) { + STARTUP_PRINT( "buffer_length = %zu\r\n", message->buffer_length ) + // handle out + if ( message->pipe_address.direction == LIBUSB_DIRECTION_OUT ) { + memcpy( databuffer, message->buffer, message->buffer_length ); + } + temporary_pipe.speed = message->pipe_address.speed; + temporary_pipe.device = message->pipe_address.device; + temporary_pipe.end_point = message->pipe_address.end_point; + temporary_pipe.max_size = message->pipe_address.max_size; + temporary_pipe.type = LIBUSB_TRANSFER_CONTROL; + temporary_pipe.direction = message->pipe_address.direction; + // query data + result = dwhci_channel_send_wait( + message->parent_device_number, + message->port_number, + &message->error, + &temporary_pipe, + 0, + databuffer, + message->buffer_length, + DWHCI_CHANNEL_STATE_DATA1, + &transferred + ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Data failed with %s\r\n", response_error( result ) ) + // set error + error.status = -result; + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate last transfer + if ( message->pipe_address.direction == LIBUSB_DIRECTION_IN ) { + message->last_transfer = message->buffer_length; + if ( transferred <= message->buffer_length ) { + message->last_transfer = message->buffer_length - transferred; + } + // copy back data + memcpy( message->buffer, databuffer, message->last_transfer ); + } else { + message->last_transfer = message->buffer_length; + } + } + // adjust temporary pipe + temporary_pipe.speed = message->pipe_address.speed; + temporary_pipe.device = message->pipe_address.device; + temporary_pipe.end_point = message->pipe_address.end_point; + temporary_pipe.max_size = message->pipe_address.max_size; + temporary_pipe.type = LIBUSB_TRANSFER_CONTROL; + temporary_pipe.direction = message->buffer_length == 0 + || message->pipe_address.direction == LIBUSB_DIRECTION_OUT + ? LIBUSB_DIRECTION_IN + : LIBUSB_DIRECTION_OUT; + // perform data request + result = dwhci_channel_send_wait( + message->parent_device_number, + message->port_number, + &message->error, + &temporary_pipe, + 0, + databuffer, + 0, + DWHCI_CHANNEL_STATE_DATA1, + &transferred + ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Final transmit failed with %s\r\n", response_error( result ) ) + // set error + error.status = -result; + // detach shared memory + _syscall_memory_shared_detach( submit_control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle transfer size not null + if ( transferred ) { + STARTUP_PRINT( "Warning non zero status transfer: %"PRIu32"\r\n", transferred ) + } + // set error to no error + message->error = LIBUSB_TRANSFER_ERROR_NO_ERROR; } // detach shared memory _syscall_memory_shared_detach( submit_control_message->shm_id ); diff --git a/bolthur/server/terminal/render.c b/bolthur/server/terminal/render.c index 0d7d1c69..f3dcad0b 100644 --- a/bolthur/server/terminal/render.c +++ b/bolthur/server/terminal/render.c @@ -284,9 +284,9 @@ ssize_t render_terminal( terminal_t* term, const char* s ) { ), action ); + free( action ); // handle error if ( -1 == result ) { - free( action ); return -EIO; } // return rendered character diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index 351254e2..7cac3a61 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -7,7 +7,7 @@ hub_DEPENDENCIES = \ hub_LDADD = \ ${abs_top_builddir}/../library/usb/libusb.la hub_SOURCES = \ + rpc/hub/attach.c \ rpc/init.c \ - hub.c \ main.c hub_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hub/hub.h b/bolthur/server/usb/device/hub/hub.h index 8fbba3af..39584f23 100644 --- a/bolthur/server/usb/device/hub/hub.h +++ b/bolthur/server/usb/device/hub/hub.h @@ -20,18 +20,6 @@ #ifndef _HUB_H #define _HUB_H -#include "../../../libusb.h" - #define HUB_ENABLE_DEBUG 1 -int hub_read_descriptor( const libusb_device_t* ); -int hub_get_status( libusb_device_t* ); -int hub_get_port_status( libusb_device_t*, uint8_t ); -int hub_change_port_feature( libusb_device_t*, libusb_hub_port_feature_t, uint8_t, bool ); -int hub_power_on( libusb_device_t* ); -int hub_port_reset( libusb_device_t*, uint8_t ); -int hub_port_connection_changed( libusb_device_t*, uint8_t); -int hub_check_connection( libusb_device_t*, uint8_t, bool ); -int hub_init( void ); - #endif diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 243bbe18..73f76afb 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -22,9 +22,9 @@ #include #include // local includes -#include "hub.h" #include "rpc.h" // library includes +#include "../../../libhelper.h" #include "../../../../library/usb/usb.h" /** @@ -45,21 +45,36 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // intialize usb library STARTUP_PRINT( "Setup usb library\r\n" ) - if ( 0 != usb_init() ) { - STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( errno ) ); + int result = usb_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); return -1; } - // setup hub interface - STARTUP_PRINT( "Setup hub interface!\r\n" ) - const int result = hub_init(); + // registering handler + STARTUP_PRINT( "Registering handler at usbd\r\n" ) + result = usb_register_handler( LIBUSB_INTERFACE_CLASS_HUB ); if ( 0 != result ) { - STARTUP_PRINT( "Unable initialize hub\r\n" ); + STARTUP_PRINT( "Unable to register handler at usbd\r\n" ) return -1; } - while ( true ) { - __asm__ __volatile__ ( "nop" ); + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); + + // add device file + STARTUP_PRINT( "Sending device to vfs\r\n" ) + uint32_t device_info[] = { + HUB_ATTACH, + }; + if ( !dev_add_file( HUB_DEVICE_PATH, device_info, 1 ) ) { + STARTUP_PRINT( "Unable to add dev usbd\r\n" ) + return -1; } - return -1; + + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/usb/device/hub/rpc.h b/bolthur/server/usb/device/hub/rpc.h index 561839c5..fa54a49e 100644 --- a/bolthur/server/usb/device/hub/rpc.h +++ b/bolthur/server/usb/device/hub/rpc.h @@ -24,5 +24,6 @@ #include bool rpc_init( void ); +void rpc_hub_attach( size_t, pid_t, size_t, size_t ); #endif diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c similarity index 55% rename from bolthur/server/usb/device/hub/hub.c rename to bolthur/server/usb/device/hub/rpc/hub/attach.c index cef827c0..cd911ddb 100644 --- a/bolthur/server/usb/device/hub/hub.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -21,23 +21,39 @@ #include #include #include -#include // local includes -#include "hub.h" -// library includes -#include "../../../../library/usb/usb.h" +#include "../../hub.h" +#include "../../rpc.h" +#include "../../../../../libusb.h" +#include "../../../../../../library/usb/usb.h" -// disable malloc warning since read descriptor is wanted to allocate stuff -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +static void custom_nanosleep( const struct timespec* rqtp ) { + if ( 0 > rqtp->tv_nsec ) { + errno = EINVAL; + return; + } + // get clock frequency + size_t frequency = _syscall_timer_frequency(); + // calculate second timeout + size_t timeout = ( size_t )( rqtp->tv_sec * frequency ); + size_t tick; + // add nanosecond offset + timeout += ( size_t )( ( double )rqtp->tv_nsec * ( double )frequency / 1000000000.0 ); + // add tick count to get an end time + timeout += _syscall_timer_tick_count(); + // loop until timeout is reached + while ( ( tick = _syscall_timer_tick_count() ) < timeout ) { + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif + __asm__ __volatile__( "nop" ); + } + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif +} -/** - * @fn int hub_read_descriptor(libusb_device_t*) - * @brief Wrapper to read out hub descriptor in driver - * @param dev - * @return - */ -int hub_read_descriptor( const libusb_device_t* dev ) { +static int attach_hub_read_descriptor( const uint32_t device_number, void** descriptor ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Reading usb hub descriptor\r\n" ) @@ -45,8 +61,8 @@ int hub_read_descriptor( const libusb_device_t* dev ) { // space for buffer on stack libusb_descriptor_header_t header; // get hub descriptor - int result = usb_get_descriptor( dev, LIBUSB_DESCRIPTOR_HUB, 0, 0, &header, - sizeof( header ), sizeof( header ), 0x20 ); + int result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, + &header, sizeof( header ), sizeof( header ), 0x20 ); // handle error if ( 0 != result ) { // debug output @@ -58,27 +74,26 @@ int hub_read_descriptor( const libusb_device_t* dev ) { return result; } // allocate space in driver data - if ( ! ( ( libusb_hub_device_t* )dev->driver_data )->descriptor ) { + if ( ! *descriptor ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Allocating memory for hub descriptor" ); + STARTUP_PRINT( "Allocating memory for hub descriptor\r\n" ); #endif // allocate memory - ( ( libusb_hub_device_t* )dev->driver_data )->descriptor = malloc( header.descriptor_length ); + *descriptor = malloc( header.descriptor_length ); // handle error - if ( ! ( ( libusb_hub_device_t* )dev->driver_data )->descriptor ) { + if ( ! *descriptor ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to allocate memory for hub descriptor" ); + STARTUP_PRINT( "Unable to allocate memory for hub descriptor\r\n" ); #endif // return nomem return ENOMEM; } } // read descriptor itself - result = usb_get_descriptor( dev, LIBUSB_DESCRIPTOR_HUB, 0, 0, - ( ( libusb_hub_device_t* )dev->driver_data )->descriptor, - header.descriptor_length, header.descriptor_length, 0x20 ); + result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, + *descriptor, header.descriptor_length, header.descriptor_length, 0x20 ); // handle error if ( 0 != result ) { // debug output @@ -92,37 +107,29 @@ int hub_read_descriptor( const libusb_device_t* dev ) { return 0; } -// enable warnings again -#pragma GCC diagnostic pop - -/** - * @fn int hub_get_status(libusb_device_t*) - * @brief Method to retrieve host status - * @param dev - * @return - */ -int hub_get_status( libusb_device_t* dev ) { +static int attach_hub_get_status( + const uint32_t device_number, + libusb_hub_device_t* hub_device +) { + // space for last transfer and error + uint32_t last_transfer; + libusb_transfer_error_t error; + // perform control message const int result = usb_control_message( - dev, - ( libusb_pipe_address_t ){ - .type = LIBUSB_TRANSFER_CONTROL, - .speed = dev->speed, - .end_point = 0, - .device = ( uint8_t )dev->number, - .direction = LIBUSB_DIRECTION_IN, - .max_size = usb_packet_size_from_number( - dev->descriptor.max_packet_size0 - ), - }, - &( ( libusb_hub_device_t* )dev->driver_data )->status, + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_IN, + &hub_device->status, sizeof( libusb_hub_full_status_t ), &( libusb_device_request_t ){ .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, .type = 0xa0, .length = sizeof( libusb_hub_full_status_t ), }, - 10 /// FIXME: REPLACE WITH CONSTANT - ); + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); // handle error if ( 0 != result ) { // debug output @@ -133,10 +140,10 @@ int hub_get_status( libusb_device_t* dev ) { return result; } // handle not enough read - if ( dev->last_transfer != sizeof( libusb_hub_full_status_t ) ) { + if ( last_transfer != sizeof( libusb_hub_full_status_t ) ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to read hub status for %s\r\n", usb_get_description( dev ) ) + STARTUP_PRINT( "Failed to read hub status for %s\r\n", usb_get_description( device_number ) ) #endif // return error return EIO; @@ -145,89 +152,21 @@ int hub_get_status( libusb_device_t* dev ) { return 0; } -/** - * @fn int hub_get_port_status( libusb_device_t*, const uint8_t) - * @brief Wrapper to read port status - * @param dev - * @param port - * @return - */ -int hub_get_port_status( libusb_device_t* dev, const uint8_t port ) { - const int result = usb_control_message( - dev, - ( libusb_pipe_address_t ){ - .type = LIBUSB_TRANSFER_CONTROL, - .speed = dev->speed, - .end_point = 0, - .device = ( uint8_t )dev->number, - .direction = LIBUSB_DIRECTION_IN, - .max_size = usb_packet_size_from_number( - dev->descriptor.max_packet_size0 - ), - }, - &( ( libusb_hub_device_t* )dev->driver_data )->port_status[ port ], - sizeof( libusb_hub_port_full_status_t ), - &( libusb_device_request_t ){ - .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, - .type = 0xa3, - .index = port + 1, - .length = sizeof( libusb_hub_port_full_status_t ), - }, - 10 - ); - // handle result wrong - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Fetching port status failed\r\n" ) - #endif - // return result - return result; - } - // handle wrong size - if ( dev->last_transfer != sizeof( libusb_hub_port_full_status_t ) ) { - // debug output - #if defined( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to read port %"PRIu8" status for %s. Received %"PRIu32" but expected %d\r\n", - port, usb_get_description( dev ), dev->last_transfer, sizeof( libusb_hub_port_full_status_t ) ) - #endif - // return io error - return EIO; - } - // return success - return 0; -} - -/** - * @fn int hub_change_port_feature(libusb_device_t*, libusb_hub_port_feature_t, uint8_t, bool) - * @brief Method to change port feature - * @param dev - * @param feature - * @param port - * @param set - * @return - */ -int hub_change_port_feature( - libusb_device_t* dev, +static int attach_hub_change_port_feature( + const uint32_t device_number, const libusb_hub_port_feature_t feature, const uint8_t port, const bool set ) { + uint32_t last_transfer; + libusb_transfer_error_t error; return usb_control_message( - dev, - ( libusb_pipe_address_t ){ - .type = LIBUSB_TRANSFER_CONTROL, - .speed = dev->speed, - .end_point = 0, - .device = ( uint8_t )dev->number, - .direction = LIBUSB_DIRECTION_OUT, - .max_size = usb_packet_size_from_number( - dev->descriptor.max_packet_size0 - ), - }, + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_OUT, NULL, 0, - &( libusb_device_request_t ){ + &( libusb_device_request_t ) { .request = set ? LIBUSB_DEVICE_REQUEST_SET_FEATURE : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, @@ -235,32 +174,54 @@ int hub_change_port_feature( .value = ( uint16_t )feature, .index = port + 1, }, - 10 /// FIXME: REPLACE WITH CONSTANT + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer ); + /* + return usb_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_OUT, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + NULL, + 0, + &( libusb_device_request_t ){ + .request = set + ? LIBUSB_DEVICE_REQUEST_SET_FEATURE + : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, + .type = 0x23, + .value = ( uint16_t )feature, + .index = port + 1, + }, + 10 /// FIXME: REPLACE WITH CONSTANT + );*/ } -/** - * @fn int hub_power_on(libusb_device_t*) - * @brief Method to power on hub - * @param dev - * @return - */ -int hub_power_on( libusb_device_t* dev ) { - // cache device data and descriptor locally - const libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; - const libusb_hub_descriptor_t* descriptor = device_data->descriptor; +static int attach_hub_power_on( + const uint32_t device_number, + const libusb_hub_device_t* hub_device, + const libusb_hub_descriptor_t* descriptor +) { // debug output #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Powering up %s\r\n", usb_get_description( dev ) ) + STARTUP_PRINT( "Powering up %s\r\n", usb_get_description( device_number ) ) #endif // loop through all children and power on the port - for ( uint32_t child = 0; child < device_data->max_children; child++ ) { + for ( uint32_t child = 0; child < hub_device->max_children; child++ ) { #if defined( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Power up port %"PRIu32" of %s\r\n", child, usb_get_description( dev ) ) + STARTUP_PRINT( "Power up port %"PRIu32" of %s\r\n", child, usb_get_description( device_number ) ) #endif // try to change port feature - [[maybe_unused]] const int result = hub_change_port_feature( - dev, + [[maybe_unused]] const int result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_POWER, ( uint8_t )child, true @@ -270,7 +231,7 @@ int hub_power_on( libusb_device_t* dev ) { // debug output only #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to power on port %"PRIu32" of %s: %s\r\n", - child, usb_get_description( dev ), strerror( result ) ) + child, usb_get_description( device_number ), strerror( result ) ) #endif } } @@ -278,42 +239,106 @@ int hub_power_on( libusb_device_t* dev ) { const long milliseconds = descriptor->power_good_delay * 2; STARTUP_PRINT( "sleeping %ld milliseconds\r\n", milliseconds ) // sleep a bit - nanosleep( &(struct timespec){ + custom_nanosleep( &(struct timespec){ .tv_sec = milliseconds / 1000, .tv_nsec = ( milliseconds % 1000 ) * 1000000, - }, NULL ); + } ); // return success return 0; } -/** - * @fn int hub_port_reset(libusb_device_t*, uint8_t) - * @brief Wrapper to reset host port - * @param dev - * @param port - * @return - */ -int hub_port_reset( libusb_device_t* dev, const uint8_t port ) { - // cache driver data and status - libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; +static int attach_hub_get_port_status( + const uint32_t device_number, + libusb_hub_device_t* hub, + const uint8_t port +) { + uint32_t last_transfer; + libusb_transfer_error_t error; + const int result = usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_IN, + &hub->port_status[ port ], + sizeof( libusb_hub_port_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa3, + .index = port + 1, + .length = sizeof( libusb_hub_port_full_status_t ), + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + );/* + const int result = usb_control_message( + dev, + ( libusb_pipe_address_t ){ + .type = LIBUSB_TRANSFER_CONTROL, + .speed = dev->speed, + .end_point = 0, + .device = ( uint8_t )dev->number, + .direction = LIBUSB_DIRECTION_IN, + .max_size = usb_packet_size_from_number( + dev->descriptor.max_packet_size0 + ), + }, + &( ( libusb_hub_device_t* )dev->driver_data )->port_status[ port ], + sizeof( libusb_hub_port_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa3, + .index = port + 1, + .length = sizeof( libusb_hub_port_full_status_t ), + }, + 10 + );*/ + // handle result wrong + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Fetching port status failed\r\n" ) + #endif + // return result + return result; + } + // handle wrong size + if ( last_transfer != sizeof( libusb_hub_port_full_status_t ) ) { + // debug output + #if defined( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to read port %"PRIu8" status for %s. Received %"PRIu32" but expected %d\r\n", + port, usb_get_description( device_number ), last_transfer, sizeof( libusb_hub_port_full_status_t ) ) + #endif + // return io error + return EIO; + } + // return success + return 0; +} + +static int attach_hub_port_reset( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const uint8_t port +) { + // cache status const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; uint32_t retry; int result; // debug output #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Resetting port %"PRIu8" of device %s\r\n", port, usb_get_description( dev ) ) + STARTUP_PRINT( "Resetting port %"PRIu8" of device %s\r\n", port, usb_get_description( device_number ) ) #endif // retry three times for ( retry = 0; retry < 3; retry++ ) { // try to reset - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_RESET, port, true ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET, port, true ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to reset port %"PRIu8" of device %s\r\n", - port, usb_get_description( dev ) ) + port, usb_get_description( device_number ) ) #endif // return result return result; @@ -323,18 +348,18 @@ int hub_port_reset( libusb_device_t* dev, const uint8_t port ) { do { // delay 20 milliseconds const long milliseconds = 20; - nanosleep( &(struct timespec){ + custom_nanosleep( &(struct timespec){ .tv_sec = milliseconds / 1000, .tv_nsec = ( milliseconds % 1000 ) * 1000000, - }, NULL ); + } ); // read port data - result = hub_get_port_status( dev, port ); + result = attach_hub_get_port_status( device_number, device_data, port ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to get status of port %"PRIu8" from %s\r\n", - port, usb_get_description( dev ) ) + port, usb_get_description( device_number ) ) #endif // return result return result; @@ -366,19 +391,19 @@ int hub_port_reset( libusb_device_t* dev, const uint8_t port ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Cannot enable port %"PRIu8" on %s\r\n", - port, usb_get_description( dev ) ) + port, usb_get_description( device_number ) ) #endif // return error return EIO; } // clear reset - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to clear port %"PRIu8" reset of %s\r\n", - port, usb_get_description( dev ) ) + port, usb_get_description( device_number ) ) #endif // return result return result; @@ -387,36 +412,33 @@ int hub_port_reset( libusb_device_t* dev, const uint8_t port ) { return 0; } -/** - * @fn int hub_port_connection_changed(libusb_device_t*, const uint8_t) - * @brief Handle hub connection changed - * @param dev - * @param port - * @return - */ -int hub_port_connection_changed( libusb_device_t* dev, const uint8_t port ) { - // cache driver data and status - libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; - libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; +static int attach_hub_port_connection_changed( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const uint8_t port +) { + // cache status + const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; // get hub port status - int result = hub_get_port_status( dev, port ); + int result = attach_hub_get_port_status( device_number, device_data, port ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to get status (2) for %s with port %"PRIu8"\r\n", - usb_get_description( dev ), port + 1 ) + usb_get_description( device_number ), port + 1 ) #endif // return result return result; } // change connection feature - result = hub_change_port_feature( dev, LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE, port, false ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to clear connection change on %s with port %"PRIu8"\r\n", - usb_get_description( dev ), port + 1 ) + usb_get_description( device_number ), port + 1 ) #endif // return result return result; @@ -426,30 +448,30 @@ int hub_port_connection_changed( libusb_device_t* dev, const uint8_t port ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Disconnected %s with port %"PRIu8"\r\n", - usb_get_description( dev ), port + 1 ) + usb_get_description( device_number ), port + 1 ) #endif /// FIXME: HANDLE! } // reset hub port - result = hub_port_reset( dev, port ); + result = attach_hub_port_reset( device_number, device_data, port ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Could not reset port %"PRIu8" of %s for new device\r\n", - port + 1, usb_get_description( dev ) ) + port + 1, usb_get_description( device_number ) ) #endif // return result return result; } // get hub port status - result = hub_get_port_status( dev, port ); + result = attach_hub_get_port_status( device_number, device_data, port ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to get status (3) for %s with port %"PRIu8"\r\n", - usb_get_description( dev ), port + 1 ) + usb_get_description( device_number ), port + 1 ) #endif // return result return result; @@ -461,7 +483,7 @@ int hub_port_connection_changed( libusb_device_t* dev, const uint8_t port ) { speed = LIBUSB_SPEED_LOW; } // attach new device - result = usb_attach_device( dev->number, port, speed ); + result = usb_attach_device( device_number, port, speed ); // handle error if ( 0 != result ) { // debug output @@ -506,20 +528,26 @@ int hub_port_connection_changed( libusb_device_t* dev, const uint8_t port ) { return OK;*/ } -/** - * @fn int hub_check_connection(libusb_device_t*, uint8_t, bool) - * @brief Check hub for connection - * @param dev - * @param port - * @param is_roothub - * @return - */ -int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_roothub ) { +static int attach_hub_check_connection( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const libusb_hub_descriptor_t* descriptor, + const uint8_t port +) { // cache hub device - libusb_hub_device_t* device_data = ( libusb_hub_device_t* )dev->driver_data; const bool previously_connected = device_data->port_status[ port ].status.connected; + uint32_t roothub_device_number; + int result = usb_get_root_hub( &roothub_device_number ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to retrieve root hub: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } // get port status - int result = hub_get_port_status( dev, port ); + result = attach_hub_get_port_status( device_number, device_data, port ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -531,28 +559,32 @@ int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_root // cache full status libusb_hub_port_full_status_t* port_status = &device_data->port_status[ port ]; // handle connected to root device - STARTUP_PRINT( "dev->number = %"PRIu32" connected = %d, previously_connected = %d\r\n", - dev->number, port_status->status.connected ? 1 : 0, previously_connected ? 1 : 0 ) + STARTUP_PRINT( "device_number = %"PRIu32" connected = %d, previously_connected = %d\r\n", + device_number, port_status->status.connected ? 1 : 0, previously_connected ? 1 : 0 ) // handle directly connected to root hub - if ( is_roothub && port_status->status.connected != previously_connected ) { + if ( + device_number == roothub_device_number + && port_status->status.connected != previously_connected + ) { + STARTUP_PRINT( "Root hub which is connected and was previously not or vice versa\r\n" ) port_status->change.connected_changed = true; } // handle connection changed if ( port_status->change.connected_changed ) { STARTUP_PRINT( "Connected changed!\r\n" ) - hub_port_connection_changed( dev, port ); + attach_hub_port_connection_changed( device_number, device_data, port ); } if ( port_status->change.enabled_changed ) { STARTUP_PRINT( "ENABLED CHANGED!\r\n" ) // clear enable change flag - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE, port, false ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to clear enable change for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( dev ) ) + port + 1, usb_get_description( device_number ) ) #endif } @@ -561,7 +593,7 @@ int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_root #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "%s. Port %d has been disabled but is connected. This can be caused by interference. Enabling it again\r\n", - usb_get_description( dev ), port + 1 ) + usb_get_description( device_number ), port + 1 ) #endif }/* // This may indicate EM interference. @@ -573,52 +605,52 @@ int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_root if ( port_status->status.suspended ) { STARTUP_PRINT( "SUSPENDED!\r\n" ) // clear enable change flag - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_SUSPEND, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_SUSPEND, port, false ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to suspend port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( dev ) ) + port + 1, usb_get_description( device_number ) ) #endif } } if ( port_status->change.over_current_changed ) { STARTUP_PRINT( "OVER CURRENT CHANGED!\r\n" ) // clear enable change flag - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE, port, false ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to clear over current for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( dev ) ) + port + 1, usb_get_description( device_number ) ) #endif } // power on hub - result = hub_power_on( dev ); + result = attach_hub_power_on( device_number, device_data, descriptor ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to power on device %s: %s\r\n", - usb_get_description( dev ), strerror( result ) ) + usb_get_description( device_number ), strerror( result ) ) #endif } } if ( port_status->change.reset_changed ) { STARTUP_PRINT( "RESET CHANGED!\r\n" ) // clear enable change flag - result = hub_change_port_feature( - dev, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + result = attach_hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Failed to clear reset for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( dev ) ) + port + 1, usb_get_description( device_number ) ) #endif } } @@ -627,111 +659,130 @@ int hub_check_connection( libusb_device_t* dev, const uint8_t port, bool is_root } /** - * @fn int hub_init(void) - * @brief Method to initialize hub - * @return + * @fn void rpc_hub_attach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler attach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info */ -int hub_init( void ) { - // request root hub - libusb_device_t* roothub = usb_get_root_hub(); +void rpc_hub_attach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + // handle no data + if( ! data_info ) { + STARTUP_PRINT( "NO DATA PASSED!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( + data_info, &data_size, true, NULL ); + if ( ! request ) { + STARTUP_PRINT( "ERROR WHILE FETCHING DATA: %s!\r\n", strerror( errno ) ) + _syscall_rpc_cleanup(); + return; + } + // allocate space for pull_request + const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + + // print + STARTUP_PRINT( "Attach called for %"PRIu32" with interface %"PRIu32"\r\n", + message->device_number, message->interface_number ) + + // get interface information + libusb_interface_descriptor_t interface_descriptor; + int result = usb_get_interface( + message->device_number, message->interface_number, &interface_descriptor ); // handle error - if ( ! roothub ) { - const int e = errno; - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to retrieve roothub: %s\r\n", strerror( errno ) ); - #endif - // return error - return e; + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get interface data\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // get endpoint information + libusb_endpoint_descriptor_t endpoint_descriptor; + result = usb_get_endpoint( + message->device_number, message->interface_number, 0, &endpoint_descriptor ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get endpoint information\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; } + // check for multiple endpoints - if ( roothub->interfaces[ 0 ].endpoint_count != 1 ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Cannot enumerate hub with multiple endpoints: %"PRIu8"\r\n", - roothub->interfaces[ 0 ].endpoint_count ) - #endif - // return not supported - return ENOTSUP; + if ( interface_descriptor.endpoint_count != 1 ) { + STARTUP_PRINT( "Cannot enumerate hub with multiple endpoints: %"PRIu8"\r\n", + interface_descriptor.endpoint_count ) + _syscall_rpc_cleanup(); + free( request ); + return; } // handle only one output - if ( LIBUSB_DIRECTION_OUT == roothub->endpoints[ 0 ][ 0 ].endpoint_address.direction ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Cannot enumerate hub with only one output endpoint\r\n" ) - #endif - // return not supported - return ENOTSUP; + if ( LIBUSB_DIRECTION_OUT == endpoint_descriptor.endpoint_address.direction ) { + STARTUP_PRINT( "Cannot enumerate hub with only one output endpoint\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; } // handle no interrupt endpoint - if ( LIBUSB_TRANSFER_INTERRUPT != roothub->endpoints[ 0 ][ 0 ].attributes.transfer ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Cannot enumerate hub without interrupt endpoint\r\n" ) - #endif - // return not supported - return ENOTSUP; + if ( LIBUSB_TRANSFER_INTERRUPT != endpoint_descriptor.attributes.transfer ) { + STARTUP_PRINT( "Cannot enumerate hub without interrupt endpoint\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; } + // allocate driver data - roothub->driver_data = malloc( sizeof( libusb_hub_device_t ) ); - if ( ! roothub->driver_data ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to allocate space for usb hub device\r\n" ) - #endif - // return enomem - return ENOMEM; - } - // clear out space - memset( roothub->driver_data, 0, sizeof( libusb_hub_device_t ) ); - // populate header of driver data - roothub->driver_data->data_size = sizeof( libusb_hub_device_t ); - roothub->driver_data->device_driver = DEVICE_DRIVER_HUB; - // cache usb hub device locally - libusb_hub_device_t* hub = ( libusb_hub_device_t* )roothub->driver_data; - // read hub descriptor - int result = hub_read_descriptor( roothub ); + libusb_hub_device_t* hub = malloc( sizeof( *hub ) ); + if ( ! hub ) { + STARTUP_PRINT( "Unable to allocate driver data\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // clear out + memset( hub, 0, sizeof( *hub ) ); + // read descriptor + libusb_hub_descriptor_t* descriptor = nullptr; + result = attach_hub_read_descriptor( message->device_number, ( void** )&descriptor ); // handle error if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to fetch hub descriptor: %s\r\n", strerror( result ) ); - #endif - // return result - return result; - } - // get hub descriptor - const libusb_hub_descriptor_t* hub_descriptor = hub->descriptor; - // handle to many children - if ( MAX_CHILDREN_PER_DEVICE < hub_descriptor->port_count ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Hub %s is to big for this driver to handle. Only the first " - "%d ports will be used\r\n", usb_get_description( roothub ), - MAX_CHILDREN_PER_DEVICE ) - #endif - // set max children - hub->max_children = MAX_CHILDREN_PER_DEVICE; - } else { - hub->max_children = hub_descriptor->port_count; - } + STARTUP_PRINT( "Unable to read hub descriptor\r\n" ) + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; + } + // populate hub max children + hub->max_children = descriptor->port_count; + STARTUP_PRINT( "hub->max_children = %"PRIu32"\r\n", hub->max_children ) // validate power switching mode if ( - LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub_descriptor->attributes.power_switching_mode - && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub_descriptor->attributes.power_switching_mode + LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.power_switching_mode + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.power_switching_mode ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unknown power type %d on %s\r\n", - hub_descriptor->attributes.power_switching_mode, - usb_get_description( roothub ) ) + descriptor->attributes.power_switching_mode, + usb_get_description( message->device_number ) ) #endif - // return not supported - return ENOTSUP; + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; } // some debug output #if defined( HUB_ENABLE_DEBUG ) - switch ( hub_descriptor->attributes.power_switching_mode ) { + switch ( descriptor->attributes.power_switching_mode ) { case LIBUSB_HUB_PORT_CONTROL_GLOBAL: STARTUP_PRINT( "Power mode is global\r\n" ) break; @@ -739,7 +790,7 @@ int hub_init( void ) { STARTUP_PRINT( "Power mode is individual\r\n" ) break; } - if ( hub_descriptor->attributes.compound ) { + if ( descriptor->attributes.compound ) { STARTUP_PRINT( "Hub nature is compound\r\n" ) } else { STARTUP_PRINT( "Hub nature is standalone\r\n" ) @@ -747,21 +798,23 @@ int hub_init( void ) { #endif // validate over current protection if ( - LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub_descriptor->attributes.over_current_protection - && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub_descriptor->attributes.over_current_protection + LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.over_current_protection + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.over_current_protection ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unknown hub over current type %d on %s\r\n", - hub_descriptor->attributes.power_switching_mode, - usb_get_description( roothub ) ) + descriptor->attributes.power_switching_mode, + usb_get_description( message->device_number ) ) #endif - // return not supported - return ENOTSUP; + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; } // some debug output #if defined( HUB_ENABLE_DEBUG ) - switch ( hub_descriptor->attributes.over_current_protection ) { + switch ( descriptor->attributes.over_current_protection ) { case LIBUSB_HUB_PORT_CONTROL_GLOBAL: STARTUP_PRINT( "Hub over current protection is global\r\n" ) break; @@ -769,21 +822,23 @@ int hub_init( void ) { STARTUP_PRINT( "Hub over current protection is individual\r\n" ) break; } - STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", hub_descriptor->power_good_delay * 2 ) - STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", hub_descriptor->maximum_hub_power * 2 ) - STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", hub_descriptor->port_count ) + STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", descriptor->power_good_delay * 2 ) + STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", descriptor->maximum_hub_power * 2 ) + STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", descriptor->port_count ) #endif // retrieve status - result = hub_get_status( roothub ); + result = attach_hub_get_status( message->device_number, hub ); // handle error if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to fetch hub status for %s: %s\r\n", - usb_get_description( roothub ), strerror( result ) ) + usb_get_description( message->device_number ), strerror( result ) ) #endif - // return result - return result; + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; } // cache status locally libusb_hub_full_status_t* status = &hub->status; @@ -795,25 +850,29 @@ int hub_init( void ) { !status->status.over_current ? "No" : "Yes" ) #endif // power on hub - result = hub_power_on( roothub ); + result = attach_hub_power_on( message->device_number, hub, descriptor ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to power on hub!\r\n" ) #endif - // return result - return result; + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; } // fetch status again - result = hub_get_status( roothub ); + result = attach_hub_get_status( message->device_number, hub ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to get hub status for %s: %s\r\n", - usb_get_description( roothub ), strerror( result ) ) + usb_get_description( message->device_number ), strerror( result ) ) #endif - // return result - return result; + _syscall_rpc_cleanup(); + free( hub ); + free( request ); + return; } // some debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -822,12 +881,15 @@ int hub_init( void ) { STARTUP_PRINT( "Hub over current condition: %s\r\n", !status->status.over_current ? "No" : "Yes" ) #endif - // check for connection for ( uint8_t port = 0; port < hub->max_children; port++ ) { STARTUP_PRINT( "Checking port %"PRIu8"\r\n", port ) - hub_check_connection( roothub, port, true ); - } - // return success - return ENOSYS; + attach_hub_check_connection( message->device_number, hub, descriptor, port ); + } + // free hub + free( hub ); + // free request + free( request ); + // cleanup rpc + _syscall_rpc_cleanup(); } diff --git a/bolthur/server/usb/device/hub/rpc/init.c b/bolthur/server/usb/device/hub/rpc/init.c index 36eab1e5..89771035 100644 --- a/bolthur/server/usb/device/hub/rpc/init.c +++ b/bolthur/server/usb/device/hub/rpc/init.c @@ -21,6 +21,7 @@ #include // local includes #include "../rpc.h" +#include "../../../../libusb.h" /** * @fn bool rpc_init(void) @@ -28,5 +29,11 @@ * @return */ bool rpc_init( void ) { + // register attach handler + bolthur_rpc_bind( HUB_ATTACH, rpc_hub_attach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register attach handler!\r\n" ) + return false; + } return true; } diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index 9b24675b..4e2ca14f 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -7,10 +7,13 @@ usbd_SOURCES = \ rpc/control/message.c \ rpc/get/description.c \ rpc/get/descriptor.c \ + rpc/get/endpoint.c \ + rpc/get/interface.c \ rpc/get/roothub.c \ rpc/handler/register.c \ rpc/handler/unregister.c \ rpc/init.c \ + call.c \ main.c \ usbd.c usbd_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/usbd/call.c b/bolthur/server/usb/usbd/call.c new file mode 100644 index 00000000..9f7b1be3 --- /dev/null +++ b/bolthur/server/usb/usbd/call.c @@ -0,0 +1,115 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include "call.h" +#include "usbd.h" + +/** + * @fn int call_attach( libusb_device_t* dev, uint32_t ); + * @brief Method to call actual attach method + * @param dev + * @param interface_number + * @return + */ +int call_attach( libusb_device_t* dev, const uint32_t interface_number ) { + // get handler for attaching root hub + pid_t handler; + const int result = usbd_get_handler( dev->interfaces[ 0 ].class, &handler ); + if ( 0 != result ) { + // debug output + #if defined( CALL_ENABLE_DEBUG ) + STARTUP_PRINT( "Error while fetching handler for %d: %s\r\n", + dev->interfaces[ 0 ].class, strerror( result ) ) + #endif + // return result + return result; + } + // handle no handler bound + if ( -1 == handler ) { + // debug output + #if defined( CALL_ENABLE_DEBUG ) + STARTUP_PRINT( "No handler found for %d\r\n", dev->interfaces[ 0 ].class ) + #endif + // return success + return 0; + } + // set handler pids for device + dev->device_detached_handler = handler; + dev->device_deallocate_handler = handler; + dev->device_check_for_change_handler = handler; + dev->device_child_detached_handler = handler; + dev->device_child_reset_handler = handler; + dev->device_check_connection_handler = handler; + /// FIXME: GENERATE CORRECT REQUEST + const size_t request_size = sizeof( vfs_ioctl_perform_request_t ) + + sizeof( usb_generic_attach_t ); + vfs_ioctl_perform_request_t* request = malloc( request_size ); + if ( ! request ) { + // debug output + #if defined( CALL_ENABLE_DEBUG ) + STARTUP_PRINT( "Error while allocating rpc request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, request_size ); + // populate container + ( ( usb_generic_attach_t* )request->container )->device_number = dev->number; + ( ( usb_generic_attach_t* )request->container)->interface_number = interface_number; + if ( dev->parent ) { + ( ( usb_generic_attach_t* )request->container )->parent_device_number = dev->parent->number; + } + // attach is defined as first custom message + bolthur_rpc_raise_generic( + RPC_CUSTOM_START, + handler, + request, + request_size, + NULL, + RPC_CUSTOM_START, + request, + request_size, + 0, + 0, + NULL, + true, + false + ); + // handle error + if ( errno ) { + // cache errno + const int e = errno; + // debug output + #if defined( CALL_ENABLE_DEBUG ) + STARTUP_PRINT( "Error while sending request to handler: %s\r\n", + strerror( e ) ) + #endif + // free request + free( request ); + // return error + return e; + } + // free request + free( request ); + // return success + return 0; +} diff --git a/bolthur/server/usb/usbd/call.h b/bolthur/server/usb/usbd/call.h new file mode 100644 index 00000000..519b8ca4 --- /dev/null +++ b/bolthur/server/usb/usbd/call.h @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef CALL_H +#define CALL_H + +#include "../../libusb.h" + +#define CALL_ENABLE_DEBUG 1 + +int call_attach( libusb_device_t*, uint32_t ); + +#endif diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index a127fdf0..cee943a9 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -22,6 +22,7 @@ #include #include "usbd.h" #include "rpc.h" +#include "../../libhcd.h" #include "../../libhelper.h" /** @@ -40,11 +41,11 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } - // setup usbd interface - STARTUP_PRINT( "Setup usbd interface!\r\n" ) - const int result = usbd_init(); + // initialize usbd handler + STARTUP_PRINT( "Setup handler array\r\n" ) + int result = usbd_init_handler(); if ( 0 != result ) { - STARTUP_PRINT( "Unable to init usbd: %s\r\n", strerror( result ) ); + STARTUP_PRINT( "Unable to setup handler: %s\r\n", strerror( result ) ); return -1; } @@ -55,19 +56,32 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // add device file STARTUP_PRINT( "Sending device to vfs\r\n" ) uint32_t device_info[] = { - USBD_REGISTER_DEVICE_HANDLER, - USBD_UNREGISTER_DEVICE_HANDLER, - USBD_CONTROL_MESSAGE, + USBD_REGISTER_HANDLER, + USBD_UNREGISTER_HANDLER, + USBD_GET_DESCRIPTOR, + USBD_GET_ENDPOINT, + USBD_GET_INTERFACE, USBD_GET_DESCRIPTION, + USBD_CONTROL_MESSAGE, USBD_GET_ROOTHUB, - USBD_GET_DESCRIPTOR, USBD_ATTACH_DEVICE, }; - if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 7 ) ) { + if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 9 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } + // wait for hcd to be populated + vfs_wait_for_path( HCD_DEVICE_PATH ); + + // setup usbd interface + STARTUP_PRINT( "Setup usbd\r\n" ) + result = usbd_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to init usbd: %s\r\n", strerror( result ) ); + return -1; + } + // wait for rpc STARTUP_PRINT( "Wait for rpc\r\n" ) bolthur_rpc_wait_block(); diff --git a/bolthur/server/usb/usbd/rpc.h b/bolthur/server/usb/usbd/rpc.h index d184fb99..80dd23e1 100644 --- a/bolthur/server/usb/usbd/rpc.h +++ b/bolthur/server/usb/usbd/rpc.h @@ -28,6 +28,8 @@ void rpc_attach_device( size_t, pid_t, size_t, size_t ); void rpc_control_message( size_t, pid_t, size_t, size_t ); void rpc_get_description( size_t, pid_t, size_t, size_t ); void rpc_get_descriptor( size_t, pid_t, size_t, size_t ); +void rpc_get_endpoint( size_t, pid_t, size_t, size_t ); +void rpc_get_interface( size_t, pid_t, size_t, size_t ); void rpc_get_roothub( size_t, pid_t, size_t, size_t ); void rpc_handler_register( size_t, pid_t, size_t, size_t ); void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/usb/usbd/rpc/attach/device.c b/bolthur/server/usb/usbd/rpc/attach/device.c index 80b58f4f..9e49e094 100644 --- a/bolthur/server/usb/usbd/rpc/attach/device.c +++ b/bolthur/server/usb/usbd/rpc/attach/device.c @@ -41,6 +41,7 @@ void rpc_attach_device( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "ATTACH DEVICE CALLED\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -109,6 +110,9 @@ void rpc_attach_device( } // populate speed into new device new_device->speed = message->speed; + // set parent and port number + new_device->parent = device; + new_device->port_number = device->port_number; // allocate new device // perform hcd control message result = usbd_attach_device( new_device ); diff --git a/bolthur/server/usb/usbd/rpc/control/message.c b/bolthur/server/usb/usbd/rpc/control/message.c index 3cd1d7ba..1fb3642c 100644 --- a/bolthur/server/usb/usbd/rpc/control/message.c +++ b/bolthur/server/usb/usbd/rpc/control/message.c @@ -41,6 +41,7 @@ void rpc_control_message( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "CONTROL MESSAGE\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -92,15 +93,46 @@ void rpc_control_message( bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } + // find device + libusb_device_t* device = head; + while ( device ) { + if ( device->number == message->device_number ) { + break; + } + device = device->next; + } + if ( ! device ) { + error.status = -ENODEV; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } // perform hcd control message const int result = usbd_control_message( - &message->device, - message->pipe_address, + device, + ( libusb_pipe_address_t ) { + .type = message->transfer, + .speed = device->speed, + .end_point = 0, + .device = ( uint8_t )device->number, + .direction = message->direction, + .max_size = usb_packet_size_from_number( + device->descriptor.max_packet_size0 + ), + }, message->buffer_length ? message->buffer : nullptr, message->buffer_length, &message->request, message->timeout ); + // set last error and transfer + message->error = device->error; + message->last_transfer = device->last_transfer; // detach shared memory _syscall_memory_shared_detach( control_message->shm_id ); // populate status and just copy over data from request diff --git a/bolthur/server/usb/usbd/rpc/get/description.c b/bolthur/server/usb/usbd/rpc/get/description.c index 1a074671..05064cbb 100644 --- a/bolthur/server/usb/usbd/rpc/get/description.c +++ b/bolthur/server/usb/usbd/rpc/get/description.c @@ -41,6 +41,7 @@ void rpc_get_description( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "GET DESCRIPTION\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -62,23 +63,23 @@ void rpc_get_description( } // allocate space for pull_request const usbd_get_description_t* description = ( usbd_get_description_t* )request->container; - // get description with dummy device - const char* desc = usbd_get_description( - &(libusb_device_t) { - .status = description->status, - .descriptor = { - .usb_version = description->usb_version, - .product_id = description->product_id, - .vendor_id = description->vendor_id, - }, - .interfaces = { - { - .protocol = description->protocol, - .class = description->class, - } - } + // find device + const libusb_device_t* dev = head; + while ( dev ) { + if ( dev->number == description->device_number ) { + break; } - ); + dev = dev->next; + } + // handle no device + if ( ! dev ) { + error.status = -EIO; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get description with dummy device + const char* desc = usbd_get_description( dev ); STARTUP_PRINT( "desc = %s\r\n", desc ) // allocate response structure const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) diff --git a/bolthur/server/usb/usbd/rpc/get/descriptor.c b/bolthur/server/usb/usbd/rpc/get/descriptor.c index 239058f1..ccbec85f 100644 --- a/bolthur/server/usb/usbd/rpc/get/descriptor.c +++ b/bolthur/server/usb/usbd/rpc/get/descriptor.c @@ -41,6 +41,7 @@ void rpc_get_descriptor( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "GET DESCRIPTOR\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -92,9 +93,29 @@ void rpc_get_descriptor( bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } + // find device + libusb_device_t* device = head; + while ( device ) { + if ( device->number == message->device_number ) { + break; + } + device = device->next; + } + // handle not found + if ( ! device ) { + error.status = -ENODATA; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } // perform get descriptor const int result = usbd_get_descriptor( - &message->device, + device, message->type, message->index, message->lang_id, diff --git a/bolthur/server/usb/usbd/rpc/get/endpoint.c b/bolthur/server/usb/usbd/rpc/get/endpoint.c new file mode 100644 index 00000000..a2c6cd50 --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/endpoint.c @@ -0,0 +1,106 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_get_endpoint(size_t, pid_t, size_t, size_t) + * @brief Get usb endpoint data + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_endpoint( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + STARTUP_PRINT( "GET ENDPOINT\r\n" ) + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_get_endpoint_t* control_message = ( usbd_get_endpoint_t* )request->container; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // find device + libusb_device_t* device = head; + while ( device ) { + if ( device->number == control_message->device_number ) { + break; + } + device = device->next; + } + // handle not found + if ( ! device ) { + error.status = -ENODATA; + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, + &device->endpoints[ control_message->interface_number ][ control_message->endpoint_number ], + sizeof( libusb_endpoint_descriptor_t ) ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/interface.c b/bolthur/server/usb/usbd/rpc/get/interface.c new file mode 100644 index 00000000..aedb6c2a --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/interface.c @@ -0,0 +1,105 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusb.h" + +/** + * @fn void rpc_get_endpoint(size_t, pid_t, size_t, size_t) + * @brief Get usb endpoint data + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_interface( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + STARTUP_PRINT( "GET INTERFACE\r\n" ) + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + const usbd_get_endpoint_t* control_message = ( usbd_get_endpoint_t* )request->container; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // find device + libusb_device_t* device = head; + while ( device ) { + if ( device->number == control_message->device_number ) { + break; + } + device = device->next; + } + // handle not found + if ( ! device ) { + error.status = -ENODATA; + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, &device->interfaces[ control_message->interface_number ], + sizeof( libusb_endpoint_descriptor_t ) ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/roothub.c b/bolthur/server/usb/usbd/rpc/get/roothub.c index 2586e534..c03b0a8c 100644 --- a/bolthur/server/usb/usbd/rpc/get/roothub.c +++ b/bolthur/server/usb/usbd/rpc/get/roothub.c @@ -29,7 +29,7 @@ /** * @fn void rpc_get_roothub(size_t, pid_t, size_t, size_t) - * @brief Get usb roothub device + * @brief Get usb roothub device number * @param type message type * @param origin origin of the message * @param data_info data id @@ -41,6 +41,7 @@ void rpc_get_roothub( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "GET ROOT HUB\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -61,31 +62,11 @@ void rpc_get_roothub( return; } const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); - // allocate space for pull_request - const usbd_get_roothub_t* control_message = - ( usbd_get_roothub_t* )request->container; - // attach shared memory - void* shm_addr = _syscall_memory_shared_attach( - control_message->shm_id, ( uintptr_t )NULL ); - // handle error - if ( errno ) { - // set error - error.status = -errno; - // free request - free( request ); - // return from rpc - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // transform shared memory into message - libusb_device_t* dev = ( libusb_device_t* )shm_addr; // allocate response structure const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; vfs_ioctl_perform_response_t* response = malloc( response_size ); if ( ! response ) { error.status = -ENOMEM; - // detach shared memory - _syscall_memory_shared_detach( control_message->shm_id ); // free request free( request ); // return from rpc @@ -96,8 +77,6 @@ void rpc_get_roothub( libusb_device_t* roothub = usbd_get_root_hub(); if ( ! roothub ) { error.status = -EIO; - // detach shared memory - _syscall_memory_shared_detach( control_message->shm_id ); // free request free( request ); free( response ); @@ -105,13 +84,9 @@ void rpc_get_roothub( bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } - // copy over root hub - memcpy( dev, roothub, sizeof( libusb_device_t ) ); - // detach shared memory - _syscall_memory_shared_detach( control_message->shm_id ); - // populate status and just copy over data from request + // populate status and just copy over data response->status = 0; - memcpy( response->container, request->container, container_size ); + memcpy( response->container, &roothub->number, sizeof( uint32_t ) ); // return from rpc bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); // free up memory diff --git a/bolthur/server/usb/usbd/rpc/handler/register.c b/bolthur/server/usb/usbd/rpc/handler/register.c index 5491c371..08bcfa5a 100644 --- a/bolthur/server/usb/usbd/rpc/handler/register.c +++ b/bolthur/server/usb/usbd/rpc/handler/register.c @@ -42,6 +42,7 @@ void rpc_handler_register( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "REGISTER\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -63,97 +64,17 @@ void rpc_handler_register( } // allocate space for pull_request const usbd_register_device_handler_t* message = ( usbd_register_device_handler_t* )request->container; - // validate against handler enum - if ( - message->type < DEVICE_HANDLER_TYPE_DETACHED - || message->type > DEVICE_HANDLER_TYPE_CHECK_CONNECTION - ) { - error.status = -EIO; - free( request ); - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // try to find hub - libusb_device_t* current = head; - while ( current ) { - // handle matching number - if ( current->number == message->device_number ) { - break; - } - // go to next - current = current->next; - } - // handle not found - if ( ! current ) { - free( request ); - error.status = -ENXIO; - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // assert not set - bool handler_not_yet_set = true; - switch ( message->type ) { - case DEVICE_HANDLER_TYPE_DETACHED: - handler_not_yet_set = -1 == current->device_detached_handler; - break; - case DEVICE_HANDLER_TYPE_DEALLOCATE: - handler_not_yet_set = -1 == current->device_deallocate_handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: - handler_not_yet_set = -1 == current->device_check_for_change_handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_DETACHED: - handler_not_yet_set = -1 == current->device_child_detached_handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_RESET: - handler_not_yet_set = -1 == current->device_child_reset_handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: - handler_not_yet_set = -1 == current->device_check_connection_handler; - break; - } - // handle already set - if ( ! handler_not_yet_set ) { - free( request ); - error.status = -EADDRINUSE; - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // allocate response message - const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + sizeof( bool ); - vfs_ioctl_perform_response_t* response = malloc( response_size ); - if ( ! response ) { - error.status = -ENOMEM; + // register handler + const int result = usbd_register_handler( message->type, message->handler ); + // handle error + if ( 0 != result ) { + error.status = -result; free( request ); bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } - memset( response, 0, response_size ); - // just set it to the handler - switch ( message->type ) { - case DEVICE_HANDLER_TYPE_DETACHED: - handler_not_yet_set = message->handler; - break; - case DEVICE_HANDLER_TYPE_DEALLOCATE: - handler_not_yet_set = message->handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: - handler_not_yet_set = message->handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_DETACHED: - handler_not_yet_set = message->handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_RESET: - handler_not_yet_set = message->handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: - handler_not_yet_set = message->handler; - break; - } - // return success - response->status = 0; - *( bool* )response->container = true; - bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // return success without data + error.status = 0; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); free( request ); - free( response ); } diff --git a/bolthur/server/usb/usbd/rpc/handler/unregister.c b/bolthur/server/usb/usbd/rpc/handler/unregister.c index 59bc7739..0bca1794 100644 --- a/bolthur/server/usb/usbd/rpc/handler/unregister.c +++ b/bolthur/server/usb/usbd/rpc/handler/unregister.c @@ -42,6 +42,7 @@ void rpc_handler_unregister( size_t data_info, [[maybe_unused]] size_t response_info ) { + STARTUP_PRINT( "UNREGISTER\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -63,97 +64,17 @@ void rpc_handler_unregister( } // allocate space for pull_request const usbd_unregister_device_handler_t* message = ( usbd_unregister_device_handler_t* )request->container; - // validate against handler enum - if ( - message->type < DEVICE_HANDLER_TYPE_DETACHED - || message->type > DEVICE_HANDLER_TYPE_CHECK_CONNECTION - ) { - error.status = -EIO; - free( request ); - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // try to find hub - libusb_device_t* current = head; - while ( current ) { - // handle matching number - if ( current->number == message->device_number ) { - break; - } - // go to next - current = current->next; - } - // handle not found - if ( ! current ) { - free( request ); - error.status = -ENXIO; - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // assert not set - bool handler_not_yet_set = true; - switch ( message->type ) { - case DEVICE_HANDLER_TYPE_DETACHED: - handler_not_yet_set = -1 == current->device_detached_handler; - break; - case DEVICE_HANDLER_TYPE_DEALLOCATE: - handler_not_yet_set = -1 == current->device_deallocate_handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: - handler_not_yet_set = -1 == current->device_check_for_change_handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_DETACHED: - handler_not_yet_set = -1 == current->device_child_detached_handler; - break; - case DEVICE_HANDLER_TYPE_CHILD_RESET: - handler_not_yet_set = -1 == current->device_child_reset_handler; - break; - case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: - handler_not_yet_set = -1 == current->device_check_connection_handler; - break; - } - // handle already set - if ( handler_not_yet_set ) { - free( request ); - error.status = -EINVAL; - bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); - return; - } - // allocate response message - const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + sizeof( bool ); - vfs_ioctl_perform_response_t* response = malloc( response_size ); - if ( ! response ) { - error.status = -ENOMEM; + // unregister handler + const int result = usbd_unregister_handler( message->type, message->handler ); + // handle error + if ( 0 != result ) { + error.status = -result; free( request ); bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); return; } - memset( response, 0, response_size ); - // just set it to the handler - switch ( message->type ) { - case DEVICE_HANDLER_TYPE_DETACHED: - handler_not_yet_set = -1; - break; - case DEVICE_HANDLER_TYPE_DEALLOCATE: - handler_not_yet_set = -1; - break; - case DEVICE_HANDLER_TYPE_CHECK_FOR_CHANGE: - handler_not_yet_set = -1; - break; - case DEVICE_HANDLER_TYPE_CHILD_DETACHED: - handler_not_yet_set = -1; - break; - case DEVICE_HANDLER_TYPE_CHILD_RESET: - handler_not_yet_set = -1; - break; - case DEVICE_HANDLER_TYPE_CHECK_CONNECTION: - handler_not_yet_set = -1; - break; - } // return success - response->status = 0; - *( bool* )response->container = true; - bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + error.status = 0; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); free( request ); - free( response ); } diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c index e7567ee9..0d3d0075 100644 --- a/bolthur/server/usb/usbd/rpc/init.c +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -47,12 +47,24 @@ bool rpc_init( void ) { STARTUP_PRINT( "Unable to register get description handler!\r\n" ) return false; } - // register handler get description + // register handler get descriptor bolthur_rpc_bind( USBD_GET_DESCRIPTOR, rpc_get_descriptor, true ); if ( errno ) { STARTUP_PRINT( "Unable to register get descriptor handler!\r\n" ) return false; } + // register handler get endpoint + bolthur_rpc_bind( USBD_GET_ENDPOINT, rpc_get_endpoint, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get endpoint handler!\r\n" ) + return false; + } + // register handler get description + bolthur_rpc_bind( USBD_GET_INTERFACE, rpc_get_interface, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get interface handler!\r\n" ) + return false; + } // register handler get roothub bolthur_rpc_bind( USBD_GET_ROOTHUB, rpc_get_roothub, true ); if ( errno ) { @@ -60,13 +72,13 @@ bool rpc_init( void ) { return false; } // register handler register - bolthur_rpc_bind( USBD_REGISTER_DEVICE_HANDLER, rpc_handler_register, true ); + bolthur_rpc_bind( USBD_REGISTER_HANDLER, rpc_handler_register, true ); if ( errno ) { STARTUP_PRINT( "Unable to register register device handler!\r\n" ) return false; } // register handler unregister - bolthur_rpc_bind( USBD_UNREGISTER_DEVICE_HANDLER, rpc_handler_unregister, true ); + bolthur_rpc_bind( USBD_UNREGISTER_HANDLER, rpc_handler_unregister, true ); if ( errno ) { STARTUP_PRINT( "Unable to register unregister device handler!\r\n" ) return false; diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index d363e8fd..3e8891e3 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -21,14 +21,14 @@ #include #include #include +#include #include #include #include // local includes #include "usbd.h" +#include "call.h" // driver includes -#include - #include "../../libusb.h" #include "../../libhcd.h" @@ -42,6 +42,11 @@ int fd_hcd = -1; */ libusb_device_t* head = nullptr; +/** + * @brief Array of class handlers + */ +pid_t* class_handler; + /** * @brief Default timeout for control messages */ @@ -101,6 +106,10 @@ void usbd_deallocate_device( libusb_device_t* dev ) { if ( dev->full_configuration ) { free( dev->full_configuration ); } + // free up driver data + if ( dev->driver_data ) { + free( dev->driver_data ); + } // free up device free( dev ); } @@ -138,7 +147,7 @@ int usbd_allocate_device( libusb_device_t** dev, bool insert_head ) { // loop until end while ( current ) { // increment number - number++; + number = ( uint32_t )fmax( current->number, number ); // save previous prev = current; // go to next @@ -243,7 +252,9 @@ int usbd_control_message( } hcd_control_message_t* message = ( hcd_control_message_t* )shm_addr; // populate real message in shared memory - memcpy( &message->device, dev, sizeof( libusb_device_t ) ); + message->device_number = dev->number; + message->parent_device_number = dev->parent ? dev->parent->number : 0; + message->port_number = dev->port_number; memcpy( &message->pipe_address, &pipe, sizeof( pipe ) ); memcpy( &message->request, request, sizeof( *request ) ); message->buffer_length = buffer_length; @@ -291,7 +302,7 @@ int usbd_control_message( return EIO; } // response is equal to input - if ( message->device.error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { + if ( message->error & LIBUSB_TRANSFER_ERROR_PROCESSING ) { // debug output #if defined( USBD_ENABLE_DEBUG ) STARTUP_PRINT( "Message to %s timeout reached\r\n", usbd_get_description( dev ) ) @@ -304,7 +315,7 @@ int usbd_control_message( return ETIMEDOUT; } // handle error - if ( message->device.error & ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING ) { + if ( message->error & ( uint32_t )~LIBUSB_TRANSFER_ERROR_PROCESSING ) { // handle check for connection if ( dev->parent && dev->parent->device_check_connection ) { // debug output @@ -335,8 +346,8 @@ int usbd_control_message( memcpy( buffer, message->buffer, buffer_length ); } // copy over static fields into device populated via shared memory - dev->error = message->device.error; - dev->last_transfer = message->device.last_transfer; + dev->error = message->error; + dev->last_transfer = message->last_transfer; // detach shared memory _syscall_memory_shared_detach( shm_id ); // free control message @@ -1118,6 +1129,17 @@ int usbd_attach_device( libusb_device_t* dev ) { #if defined( USBD_ENABLE_DEBUG ) STARTUP_PRINT( "dev->interfaces[ 0 ].class = %d\r\n", dev->interfaces[ 0 ].class ) #endif + // call to attach the device + result = call_attach( dev, 0 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed calling attach: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } // return success return 0; } @@ -1218,3 +1240,103 @@ int usbd_init( void ) { // return success return 0; } + +/** + * @fn int usbd_init_handler(void) + * @brief Init handler + * @return + */ +int usbd_init_handler( void ) { + // allocate handler + class_handler = calloc( 256, sizeof( pid_t ) ); + // handle error + if ( ! class_handler ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate memory\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + for ( size_t i = 0; i < 256; i++ ) { + class_handler[i] = -1; + } + // return success + return 0; +} + +int usbd_register_handler( const libusb_interface_class_t type, const pid_t handler ) { + // handle not initialized + if ( ! class_handler ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Handler data not initialized\r\n" ) + #endif + // return protocol error + return EPROTO; + } + // handle already set + if ( -1 != class_handler[ type ] ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Handler already registered\r\n" ) + #endif + // return exist + return EEXIST; + } + // set handler + class_handler[ type ] = handler; + // return success + return 0; +} + +int usbd_unregister_handler( const libusb_interface_class_t type, const pid_t handler ) { + // handle not initialized + if ( ! class_handler ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Handler data not initialized\r\n" ) + #endif + // return protocol error + return EPROTO; + } + // handle already set + if ( handler != class_handler[ type ] ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Handler already registered\r\n" ) + #endif + // return exist + return EINVAL; + } + // clear handler + class_handler[ type ] = -1; + // return success + return 0; +} + +int usbd_get_handler( const libusb_interface_class_t type, pid_t* handler ) { + // handle not initialized + if ( ! class_handler ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Handler data not initialized\r\n" ) + #endif + // return protocol error + return EPROTO; + } + // handle no handler + if ( ! handler ) { + // debug output + #if defined( USBD_ENABLE_DEBUG ) + STARTUP_PRINT( "Invalid handler passed\r\n" ) + #endif + // return protocol error + return EPROTO; + } + // set handler + *handler = class_handler[ type ]; + // return success + return 0; +} diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h index 61ad41b2..426ee7ba 100644 --- a/bolthur/server/usb/usbd/usbd.h +++ b/bolthur/server/usb/usbd/usbd.h @@ -43,5 +43,9 @@ int usbd_attach_device( libusb_device_t* ); int usbd_attach_root_hub( void ); libusb_device_t* usbd_get_root_hub( void ); int usbd_init( void ); +int usbd_init_handler( void ); +int usbd_register_handler( libusb_interface_class_t, pid_t ); +int usbd_unregister_handler( libusb_interface_class_t, pid_t ); +int usbd_get_handler( libusb_interface_class_t, pid_t* ); #endif diff --git a/config/ini/raspi/bcm2709/stage3.ini b/config/ini/raspi/bcm2709/stage3.ini index 0cbb794c..dd616d8f 100644 --- a/config/ini/raspi/bcm2709/stage3.ini +++ b/config/ini/raspi/bcm2709/stage3.ini @@ -1,8 +1,3 @@ -[hcd] -path = /server/usb/hcd -device = /dev/usb/hcd -early = false - [usbd] path = /server/usb/usbd device = /dev/usb/usbd @@ -13,11 +8,6 @@ path = /server/usb/hub device = /dev/usb/hub early = false -[storage] -path = /server/usb/storage -device = /dev/usb/storage -early = false - [keyboard] path = /server/usb/keyboard device = /dev/usb/keyboard @@ -27,3 +17,13 @@ early = false path = /server/usb/mouse device = /dev/usb/mouse early = false + +[storage] +path = /server/usb/storage +device = /dev/usb/storage +early = false + +[hcd] +path = /server/usb/hcd +device = /dev/usb/hcd +early = false diff --git a/notes-usb.md b/notes-usb.md new file mode 100644 index 00000000..e48a60b5 --- /dev/null +++ b/notes-usb.md @@ -0,0 +1,29 @@ +# Notes regarding usb implementation + +## Startup order + +- usbd + - setup rpc handler + - provide /dev/usb/usbd + - wait for /dev/usb/hcd + - start initialization of usb by utilizing hcd +- usb hub + - setup rpc handler + - register handler at usbd + - wait for rpc +- usb keyboard + - setup rpc handler + - register handler at usbd + - wait for rpc +- usb mouse + - setup rpc handler + - register handler at usbd + - wait for rpc +- usb storage + - setup rpc handler + - register handler at usbd + - wait for rpc +- hcd + - setup rpc handler + - do basic initialization of dwhci + - provide /dev/usb/hcd From 39bd9d51bfc54f1f0adba3350146a807ac87c9a2 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 12:48:26 +0200 Subject: [PATCH 014/144] - Deactivated output of libusb - Added sleep to stage 3 init - Added documentation to dwhci functions - Encapsulated all startup prints by dwhci enable debug define in dwhci - Cleaned up dwhci include - Temporarily enabled data abort exception printing - Fixed usbd_read_string to use wctob to translate wide char to char --- .../arch/arm/v7/interrupt/handler/data.c | 2 + bolthur/library/usb/usb.h | 2 +- bolthur/server/boot/init/stage3.c | 2 + bolthur/server/platform/raspi/usb/hcd/dwhci.c | 136 ++++++++++++++---- bolthur/server/platform/raspi/usb/hcd/dwhci.h | 16 +-- .../platform/raspi/usb/hcd/dwhciroothub.c | 36 +++-- bolthur/server/platform/raspi/usb/hcd/main.c | 2 +- bolthur/server/usb/usbd/rpc/attach/device.c | 1 - bolthur/server/usb/usbd/rpc/control/message.c | 1 - bolthur/server/usb/usbd/rpc/get/description.c | 3 - bolthur/server/usb/usbd/rpc/get/descriptor.c | 1 - bolthur/server/usb/usbd/rpc/get/endpoint.c | 1 - bolthur/server/usb/usbd/rpc/get/interface.c | 1 - bolthur/server/usb/usbd/rpc/get/roothub.c | 1 - .../server/usb/usbd/rpc/handler/register.c | 1 - .../server/usb/usbd/rpc/handler/unregister.c | 1 - bolthur/server/usb/usbd/usbd.c | 15 +- 17 files changed, 150 insertions(+), 72 deletions(-) diff --git a/bolthur/kernel/arch/arm/v7/interrupt/handler/data.c b/bolthur/kernel/arch/arm/v7/interrupt/handler/data.c index 5c4b40c7..5dbe2d55 100644 --- a/bolthur/kernel/arch/arm/v7/interrupt/handler/data.c +++ b/bolthur/kernel/arch/arm/v7/interrupt/handler/data.c @@ -17,6 +17,8 @@ * along with bolthur/kernel. If not, see . */ +#define PRINT_EXCEPTION + #include "../../../../../lib/assert.h" #include "../../../../../lib/inttypes.h" #if defined( REMOTE_DEBUG ) diff --git a/bolthur/library/usb/usb.h b/bolthur/library/usb/usb.h index 5a829c13..d685bc9c 100644 --- a/bolthur/library/usb/usb.h +++ b/bolthur/library/usb/usb.h @@ -22,7 +22,7 @@ #include "../../server/libusb.h" -#define LIBUSB_ENABLE_DEBUG 1 +//#define LIBUSB_ENABLE_DEBUG 1 int usb_init( void ); int usb_control_message( uint32_t, libusb_transfer_t, libusb_direction_t, void*, size_t, const libusb_device_request_t*, size_t, libusb_transfer_error_t*, uint32_t* ); diff --git a/bolthur/server/boot/init/stage3.c b/bolthur/server/boot/init/stage3.c index 38080041..5503e7ea 100644 --- a/bolthur/server/boot/init/stage3.c +++ b/bolthur/server/boot/init/stage3.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "configuration.h" #include "../ramdisk.h" @@ -42,6 +43,7 @@ } while ( true ) { + sleep( 10 ); __asm__ __volatile__( "nop" ); } diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.c b/bolthur/server/platform/raspi/usb/hcd/dwhci.c index 9e5a553e..e87c662c 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.c @@ -39,9 +39,13 @@ */ int fd_iomem = -1; +/** + * @brief Data buffer used for data transfer + */ void* databuffer = nullptr; /** + * @fn response_t dwhci_read_port(uint32_t, uint32_t*) * @brief Helper to read a port * @param port * @param value @@ -105,6 +109,7 @@ response_t dwhci_read_port( const uint32_t port, uint32_t* value ) { } /** + * @fn response_t dwhci_write_port(uint32_t, uint32_t) * @brief Helper to write to a port * @param port * @param value @@ -233,6 +238,7 @@ response_t dwhci_transmit_channel( const uint8_t channel, void* buffer ) { } /** + * @fn response_t dwhci_channel_interrupt_to_error(libusb_transfer_error_t*, uint8_t, bool) * @brief Translate channel interrupt to error * @param error * @param channel @@ -247,56 +253,81 @@ response_t dwhci_channel_interrupt_to_error( libusb_transfer_error_t* error, con } result = HCD_RESPONSE_OK; if ( interrupt & HCD_CHANNEL_INTERRUPT_AHB_ERROR ) { - STARTUP_PRINT( "AHB ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "AHB ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_AHB_ERROR; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_STALL ) { - STARTUP_PRINT( "STALL ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "STALL ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_STALL; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_NEGATIVE_ACKNOWLEDGEMENT ) { - STARTUP_PRINT( "NEGATIVE ACK ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "NEGATIVE ACK ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_NO_ACKNOWLEDGE; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_ACKNOWLEDGEMENT ) { - STARTUP_PRINT( "ACK ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "ACK ERROR\r\n" ) + #endif result = HCD_RESPONSE_ERROR_TIMEOUT; } if ( interrupt & HCD_CHANNEL_INTERRUPT_NOT_YET ) { - STARTUP_PRINT( "NOT_YET ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "NOT_YET ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_NOT_YET_ERROR; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_BABBLE_ERROR ) { - STARTUP_PRINT( "BABBLE_ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "BABBLE_ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_BABBLE; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_FRAME_OVERRUN ) { - STARTUP_PRINT( "OVERRUN ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "OVERRUN ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_BUFFER_ERROR; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_DATA_TOGGLE_ERROR ) { - STARTUP_PRINT( "DATA_TOGGLE_ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "DATA_TOGGLE_ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_BIT_ERROR; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( interrupt & HCD_CHANNEL_INTERRUPT_TRANSACTION_ERROR ) { - STARTUP_PRINT( "TRANSACTION_ERROR\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "TRANSACTION_ERROR\r\n" ) + #endif *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; return HCD_RESPONSE_ERROR_UNKNOWN; } if ( !( interrupt & HCD_CHANNEL_INTERRUPT_TRANSFER_COMPLETE ) && completed ) { - STARTUP_PRINT( "COMPLETED BUT FLAG NOT COMPLETED\r\n" ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "COMPLETED BUT FLAG NOT COMPLETED\r\n" ) + #endif result = HCD_RESPONSE_ERROR_TIMEOUT; } return result; } +/** + * @fn void custom_nanosleep(const struct timespec*) + * @brief Custom nano sleep + * @param rqtp + */ static void custom_nanosleep( const struct timespec* rqtp ) { if ( 0 > rqtp->tv_nsec ) { errno = EINVAL; @@ -323,6 +354,16 @@ static void custom_nanosleep( const struct timespec* rqtp ) { //#endif } +/** + * @fn response_t dwhci_channel_send_wait_one(libusb_transfer_error_t*, uint8_t, void*, uint32_t, libusb_speed_t) + * @brief Send on channel one and wait for response + * @param error + * @param channel + * @param buffer + * @param buffer_offset + * @param speed + * @return + */ response_t dwhci_channel_send_wait_one( libusb_transfer_error_t* error, const uint8_t channel, @@ -386,7 +427,9 @@ response_t dwhci_channel_send_wait_one( } if ( interrupt & HCD_CHANNEL_INTERRUPT_HALT ) { - STARTUP_PRINT( "Halt interrupt: %#"PRIx32"!\r\n", interrupt ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "Halt interrupt: %#"PRIx32"!\r\n", interrupt ) + #endif break; } @@ -556,6 +599,17 @@ response_t dwhci_channel_send_wait_one( return HCD_RESPONSE_OK; } +/** + * @fn response_t dwhci_prepare_channel(uint32_t, uint32_t, uint8_t, uint32_t, dwhci_channel_state_t, libusb_pipe_address_t*) + * @brief Prepare channel for transfer + * @param parent_device_number + * @param port_number + * @param channel + * @param buffer_length + * @param packet_id + * @param pipe + * @return + */ response_t dwhci_prepare_channel( const uint32_t parent_device_number, const uint32_t port_number, @@ -564,8 +618,10 @@ response_t dwhci_prepare_channel( const dwhci_channel_state_t packet_id, libusb_pipe_address_t* pipe ) { - STARTUP_PRINT( "%d / %d / %"PRIu8" / %"PRIu8" / %d / %d\r\n", - pipe->max_size, pipe->speed, pipe->end_point, pipe->device, pipe->type, pipe->direction ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "%d / %d / %"PRIu8" / %"PRIu8" / %d / %d\r\n", + pipe->max_size, pipe->speed, pipe->end_point, pipe->device, pipe->type, pipe->direction + #endif // prepare characteristic const uint32_t characteristic = HCD_DWHCI_CHAN_CHARACTER_DEVICE_ADDRESS( pipe->device ) | HCD_DWHCI_CHAN_CHARACTER_END_POINT_NUMBER( pipe->end_point ) @@ -588,8 +644,10 @@ response_t dwhci_prepare_channel( | HCD_DWHCI_CHAN_XFER_SIZE_PACKET_ID( packet_id ); uint32_t packet_count = ( buffer_length + 7 ) / 8; - STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", characteristic, split_control, transfer_data, packet_count ) + #endif if ( LIBUSB_SPEED_LOW != pipe->speed ) { packet_count = ( buffer_length + usb_number_from_packet_size( pipe->max_size ) - 1 ) / usb_number_from_packet_size( pipe->max_size ); @@ -598,8 +656,10 @@ response_t dwhci_prepare_channel( packet_count = 1; } transfer_data |= HCD_DWHCI_CHAN_XFER_SIZE_PACKET_COUNT( packet_count ); - STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", - characteristic, split_control, transfer_data, packet_count ) + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "characteristic = %#"PRIx32", split_control = %#"PRIx32", transfer_data = %#"PRIx32", packet_count = %#"PRIx32"\r\n", + characteristic, split_control, transfer_data, packet_count ) + #endif // allocate mmio sequence size_t sequence_size; iomem_mmio_entry_t* sequence = util_prepare_mmio_sequence( 3, &sequence_size ); @@ -650,6 +710,20 @@ response_t dwhci_prepare_channel( return HCD_RESPONSE_OK; } +/** + * @fn response_t dwhci_channel_send_wait(uint32_t, uint32_t, libusb_transfer_error_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, dwhci_channel_state_t, uint32_t*) + * @brief Send command to channel and wait + * @param parent_device_number + * @param port_number + * @param error + * @param pipe + * @param channel + * @param buffer + * @param buffer_length + * @param packet_id + * @param transfer_out + * @return + */ response_t dwhci_channel_send_wait( const uint32_t parent_device_number, const uint32_t port_number, @@ -719,9 +793,13 @@ response_t dwhci_channel_send_wait( // return result return result; } - STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, packets ); + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, packets ); + #endif transferred = buffer_length - HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_TRANSFER_SIZE( transfer_data ); - STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ); + #if defined ( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "transferred = %#zx, packets = %"PRIu32"\r\n", transferred, HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ); + #endif if ( packets == HCD_DWHCI_CHAN_XFER_SIZE_EXTRACT_PACKET_COUNT( transfer_data ) ) { break; } @@ -1004,7 +1082,12 @@ response_t dwhci_core_flush_rx_fifo( void ) { return HCD_RESPONSE_OK; } -response_t dwhci_init2( void ) { +/** + * @fn response_t dwhci_init(void) + * @brief Init dwhci otg + * @return + */ +response_t dwhci_init( void ) { // open file descriptor for mmio actions if ( -1 == ( fd_iomem = open( IOMEM_DEVICE_PATH, O_RDWR ) ) ) { // debug output @@ -1079,11 +1162,11 @@ response_t dwhci_init2( void ) { } // cache everything locally const uint32_t vendor = sequence[ 0 ].value; - const uint32_t user = sequence[ 1 ].value; - const uint32_t hw_cfg1 = sequence[ 2 ].value; + [[maybe_unused]] const uint32_t user = sequence[ 1 ].value; + [[maybe_unused]] const uint32_t hw_cfg1 = sequence[ 2 ].value; const uint32_t hw_cfg2 = sequence[ 3 ].value; - const uint32_t hw_cfg3 = sequence[ 4 ].value; - const uint32_t hw_cfg4 = sequence[ 5 ].value; + [[maybe_unused]] const uint32_t hw_cfg3 = sequence[ 4 ].value; + [[maybe_unused]] const uint32_t hw_cfg4 = sequence[ 5 ].value; uint32_t host_cfg = sequence[ 6 ].value; // free sequence free( sequence ); @@ -1486,12 +1569,11 @@ response_t dwhci_init2( void ) { result = dwhci_write_port( ( uint32_t )PERIPHERAL_DWHCI_CORE_USB_CFG, usb_cfg ); if ( HCD_RESPONSE_OK != result ) { #if defined( DWHCI_ENABLE_DEBUG ) - STARTUP_PRINT( "Write port failed\r\n" ) + STARTUP_PRINT( "Write port failed\r\n" ) #endif return result; } - // debug output #if defined( DWHCI_ENABLE_DEBUG ) STARTUP_PRINT( "Preparing host startup\r\n" ) @@ -1704,9 +1786,9 @@ response_t dwhci_init2( void ) { channel ) #endif } - // free sequence - free( sequence ); } + // free sequence + free( sequence ); } uint32_t host_port; diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhci.h b/bolthur/server/platform/raspi/usb/hcd/dwhci.h index 8846e4ab..ae9a2bdd 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhci.h +++ b/bolthur/server/platform/raspi/usb/hcd/dwhci.h @@ -24,7 +24,7 @@ #include "../../../../libusb.h" #include "response.h" -#define DWHCI_ENABLE_DEBUG 1 +//#define DWHCI_ENABLE_DEBUG 1 extern int fd_iomem; extern void* databuffer; @@ -44,23 +44,9 @@ response_t dwhci_channel_send_wait_one( libusb_transfer_error_t*, uint8_t, void* response_t dwhci_channel_send_wait( uint32_t, uint32_t, libusb_transfer_error_t*, libusb_pipe_address_t*, uint8_t, void*, size_t, dwhci_channel_state_t, uint32_t* ); response_t dwhci_read_port( uint32_t, uint32_t* ); response_t dwhci_write_port( uint32_t, uint32_t ); - -response_t dwhci_query_vendor( uint32_t* destination ); response_t dwhci_power_on( void ); -response_t dwhci_enable_global_interrupts( void ); -response_t dwhci_disable_global_interrupts( void ); -response_t dwhci_register_interrupt( void ); -response_t dwhci_reset_device( void ); -response_t dwhci_enable_common_interrupts( void ); -response_t dwhci_init_core( void ); response_t dwhci_core_flush_tx_fifo( uint32_t ); response_t dwhci_core_flush_rx_fifo( void ); -response_t dwhci_write_host_port( uint32_t ); -response_t dwhci_read_host_port( uint32_t* ); -response_t dwhci_enable_host_interrupts( void ); -response_t dwhci_init_host( void ); -response_t dwhci_enable_root_port( void ); response_t dwhci_init( void ); -response_t dwhci_init2( void ); #endif diff --git a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c index e1070bc1..a610c331 100644 --- a/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c +++ b/bolthur/server/platform/raspi/usb/hcd/dwhciroothub.c @@ -209,7 +209,9 @@ int dwhciroothub_process( *error = LIBUSB_TRANSFER_ERROR_CONNECTION_ERROR; break; } - STARTUP_PRINT( "host_port = %"PRIx32"\r\n", host_port ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "host_port = %"PRIx32"\r\n", host_port ) + #endif // push to local variable libusb_hub_port_full_status_t status = { .status = { @@ -253,7 +255,9 @@ int dwhciroothub_process( case 0x23: switch ( ( libusb_hub_port_feature_t)request->value ) { case LIBUSB_HUB_PORT_FEATURE_ENABLE: - STARTUP_PRINT( "roothub port feature enable!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature enable!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -270,7 +274,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_SUSPEND: - STARTUP_PRINT( "roothub port feature suspend!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature suspend!\r\n" ) + #endif // allocate sequence sequence = util_prepare_mmio_sequence( 7, &sequence_size ); if ( ! sequence ) { @@ -326,7 +332,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_POWER: - STARTUP_PRINT( "roothub port feature power!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature power!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -343,7 +351,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE: - STARTUP_PRINT( "roothub port feature connection change!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature connection change!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -360,7 +370,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE: - STARTUP_PRINT( "roothub port feature enable change!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature enable change!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -377,7 +389,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE: - STARTUP_PRINT( "roothub port feature over current change!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature over current change!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { @@ -407,7 +421,9 @@ int dwhciroothub_process( case 0x23: switch ( ( libusb_hub_port_feature_t )request->value ) { case LIBUSB_HUB_PORT_FEATURE_RESET: - STARTUP_PRINT( "roothub port feature reset!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature reset!\r\n" ) + #endif // allocate sequence sequence = util_prepare_mmio_sequence( 8, &sequence_size ); if ( ! sequence ) { @@ -465,7 +481,9 @@ int dwhciroothub_process( } break; case LIBUSB_HUB_PORT_FEATURE_POWER: - STARTUP_PRINT( "roothub port feature power!\r\n" ) + #if defined( DWHCI_ENABLE_DEBUG ) + STARTUP_PRINT( "roothub port feature power!\r\n" ) + #endif // read host port dwhci_result = dwhci_read_port( ( uint32_t )PERIPHERAL_DWHCI_HOST_PORT, &host_port ); if ( HCD_RESPONSE_OK != dwhci_result ) { diff --git a/bolthur/server/platform/raspi/usb/hcd/main.c b/bolthur/server/platform/raspi/usb/hcd/main.c index 95fb9cd7..22eb8e2c 100644 --- a/bolthur/server/platform/raspi/usb/hcd/main.c +++ b/bolthur/server/platform/raspi/usb/hcd/main.c @@ -46,7 +46,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // setup hcd interface STARTUP_PRINT( "Setup hcd interface!\r\n" ) - const response_t result = dwhci_init2(); + const response_t result = dwhci_init(); if ( HCD_RESPONSE_OK != result ) { STARTUP_PRINT( "Unable to init dwhci: %s\r\n", response_error( result ) ); return -1; diff --git a/bolthur/server/usb/usbd/rpc/attach/device.c b/bolthur/server/usb/usbd/rpc/attach/device.c index 9e49e094..fbb4ec5a 100644 --- a/bolthur/server/usb/usbd/rpc/attach/device.c +++ b/bolthur/server/usb/usbd/rpc/attach/device.c @@ -41,7 +41,6 @@ void rpc_attach_device( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "ATTACH DEVICE CALLED\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/control/message.c b/bolthur/server/usb/usbd/rpc/control/message.c index 1fb3642c..8386b2e9 100644 --- a/bolthur/server/usb/usbd/rpc/control/message.c +++ b/bolthur/server/usb/usbd/rpc/control/message.c @@ -41,7 +41,6 @@ void rpc_control_message( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "CONTROL MESSAGE\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/get/description.c b/bolthur/server/usb/usbd/rpc/get/description.c index 05064cbb..356b9e5f 100644 --- a/bolthur/server/usb/usbd/rpc/get/description.c +++ b/bolthur/server/usb/usbd/rpc/get/description.c @@ -41,7 +41,6 @@ void rpc_get_description( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "GET DESCRIPTION\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { @@ -80,11 +79,9 @@ void rpc_get_description( } // get description with dummy device const char* desc = usbd_get_description( dev ); - STARTUP_PRINT( "desc = %s\r\n", desc ) // allocate response structure const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + sizeof(char) * ( strlen( desc ) + 1 ); - STARTUP_PRINT( "response_size = %zu\r\n", response_size ) vfs_ioctl_perform_response_t* response = malloc( response_size ); if ( ! response ) { error.status = -ENOMEM; diff --git a/bolthur/server/usb/usbd/rpc/get/descriptor.c b/bolthur/server/usb/usbd/rpc/get/descriptor.c index ccbec85f..6058d63d 100644 --- a/bolthur/server/usb/usbd/rpc/get/descriptor.c +++ b/bolthur/server/usb/usbd/rpc/get/descriptor.c @@ -41,7 +41,6 @@ void rpc_get_descriptor( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "GET DESCRIPTOR\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/get/endpoint.c b/bolthur/server/usb/usbd/rpc/get/endpoint.c index a2c6cd50..48ade779 100644 --- a/bolthur/server/usb/usbd/rpc/get/endpoint.c +++ b/bolthur/server/usb/usbd/rpc/get/endpoint.c @@ -41,7 +41,6 @@ void rpc_get_endpoint( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "GET ENDPOINT\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/get/interface.c b/bolthur/server/usb/usbd/rpc/get/interface.c index aedb6c2a..a1b94639 100644 --- a/bolthur/server/usb/usbd/rpc/get/interface.c +++ b/bolthur/server/usb/usbd/rpc/get/interface.c @@ -41,7 +41,6 @@ void rpc_get_interface( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "GET INTERFACE\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/get/roothub.c b/bolthur/server/usb/usbd/rpc/get/roothub.c index c03b0a8c..419ddcd2 100644 --- a/bolthur/server/usb/usbd/rpc/get/roothub.c +++ b/bolthur/server/usb/usbd/rpc/get/roothub.c @@ -41,7 +41,6 @@ void rpc_get_roothub( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "GET ROOT HUB\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/handler/register.c b/bolthur/server/usb/usbd/rpc/handler/register.c index 08bcfa5a..d9716225 100644 --- a/bolthur/server/usb/usbd/rpc/handler/register.c +++ b/bolthur/server/usb/usbd/rpc/handler/register.c @@ -42,7 +42,6 @@ void rpc_handler_register( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "REGISTER\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/rpc/handler/unregister.c b/bolthur/server/usb/usbd/rpc/handler/unregister.c index 0bca1794..a3a699a5 100644 --- a/bolthur/server/usb/usbd/rpc/handler/unregister.c +++ b/bolthur/server/usb/usbd/rpc/handler/unregister.c @@ -42,7 +42,6 @@ void rpc_handler_unregister( size_t data_info, [[maybe_unused]] size_t response_info ) { - STARTUP_PRINT( "UNREGISTER\r\n" ) vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // validate origin if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index 3e8891e3..899d0df2 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -29,6 +29,8 @@ #include "usbd.h" #include "call.h" // driver includes +#include + #include "../../libusb.h" #include "../../libhcd.h" @@ -479,7 +481,7 @@ int usbd_read_string_lang( const int result = usbd_get_string( dev, string_index, lang_id, buffer, ( size_t )fmin( 2, buffer_length ) ); // handle error - if ( 0 != result ) { + if ( 0 != result || dev->last_transfer == buffer_length ) { return result; } // read string @@ -532,9 +534,6 @@ int usbd_read_string( } // transform buffer libusb_string_descriptor_t* descriptor = ( libusb_string_descriptor_t* )buffer; - if ( ! descriptor ) { - return ENOMEM; - } // read string again result = usbd_read_string_lang( dev, string_index, lang_id[ 1 ], descriptor, buffer_length ); // handle error @@ -551,13 +550,13 @@ int usbd_read_string( const uint8_t descriptor_length = descriptor->descriptor_length; // translate data into buffer uint8_t i; - for ( i = 0; i < ( descriptor_length - 2 ) >> 2; i++ ) { - ( ( uint8_t* )buffer )[ i ] = descriptor->data[ i ] > 0xff - ? '?' : ( uint8_t )descriptor->data[ i ]; + uint8_t data_index = 0; + for ( i = 0; i < ( descriptor_length - 2 ) >> 1; i++ ) { + ( ( uint8_t* )buffer )[ i ] = ( uint8_t )wctob( descriptor->data[ data_index++ ] ); } // add null termination if ( i < buffer_length ) { - ( ( uint8_t* )buffer)[ i++ ] = '\0'; + ( ( uint8_t* )buffer)[ i ] = '\0'; } // return success return 0; From fa03091739c14aa8ac076384a934687e9dd612e0 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 13:16:39 +0200 Subject: [PATCH 015/144] - Added third hub port control enum entry for no power switching supported - Updated readme regarding qemu commands - Added qemu cdc lan to usbd_get_description - Splitted up usb server related stuff from libusb into libusbd --- README.md | 6 +- bolthur/library/usb/usb.c | 2 +- bolthur/server/libusb.h | 100 +------------- bolthur/server/libusbd.h | 125 ++++++++++++++++++ bolthur/server/usb/device/hub/main.c | 1 + .../server/usb/device/hub/rpc/hub/attach.c | 101 ++------------ bolthur/server/usb/device/hub/rpc/init.c | 2 +- bolthur/server/usb/usbd/call.h | 2 +- bolthur/server/usb/usbd/rpc/attach/device.c | 2 +- bolthur/server/usb/usbd/rpc/control/message.c | 2 +- bolthur/server/usb/usbd/rpc/get/description.c | 2 +- bolthur/server/usb/usbd/rpc/get/descriptor.c | 2 +- bolthur/server/usb/usbd/rpc/get/endpoint.c | 2 +- bolthur/server/usb/usbd/rpc/get/interface.c | 2 +- bolthur/server/usb/usbd/rpc/get/roothub.c | 2 +- .../server/usb/usbd/rpc/handler/register.c | 2 +- .../server/usb/usbd/rpc/handler/unregister.c | 2 +- bolthur/server/usb/usbd/rpc/init.c | 2 +- bolthur/server/usb/usbd/usbd.c | 6 +- bolthur/server/usb/usbd/usbd.h | 2 +- 20 files changed, 163 insertions(+), 204 deletions(-) create mode 100644 bolthur/server/libusbd.h diff --git a/README.md b/README.md index bac7e5aa..8418100d 100644 --- a/README.md +++ b/README.md @@ -108,13 +108,13 @@ Emulation of the kernel project with qemu during development may be done at all ```bash # raspberry pi zero kernel emulation -qemu-system-arm -M raspi0 -cpu arm1176 -m 512M -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2708-raspi-zero.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -s -S +qemu-system-arm -M raspi0 -cpu arm1176 -m 512M -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2708-raspi-zero.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -device usb-net -s -S # raspberry pi 2B rev 1 kernel emulation -qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel7_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2709-raspi-2-b.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "bcm2708_fb.fbwidth=1024 bcm2708_fb.fbheight=768 root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -s -S +qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel7_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2709-raspi-2-b.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "bcm2708_fb.fbwidth=1024 bcm2708_fb.fbheight=768 root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -device usb-net -s -S # raspberry pi 3B kernel emulation -qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -m 1G -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel8_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2710-raspi-3-b.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -s -S +qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -m 1G -no-reboot -serial stdio -kernel ./bolthur/kernel/target/raspi/kernel8_qemu.img -initrd ../build-aux/platform/raspi/initrd -dtb ../config/dts/raspi/bcm2710-raspi-3-b.dtb -drive file=../build-aux/platform/raspi/sdcard.img,format=raw -append "root=/dev/storage/sd1 rootfstype=ext2" -usb -device usb-mouse -device usb-kbd -device usb-net -s -S ``` ### Debugging diff --git a/bolthur/library/usb/usb.c b/bolthur/library/usb/usb.c index 38db6dc4..acd0084f 100644 --- a/bolthur/library/usb/usb.c +++ b/bolthur/library/usb/usb.c @@ -25,7 +25,7 @@ // local includes #include "usb.h" // server includes -#include "../../server/libusb.h" +#include "../../server/libusbd.h" static int fd_usbd = -1; diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index bbcff60d..69b565fc 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -406,6 +406,7 @@ typedef struct libusb_device { typedef enum { LIBUSB_HUB_PORT_CONTROL_GLOBAL = 0, LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL = 1, + LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING = 2, } libusb_hub_port_control_t; typedef struct __packed { @@ -506,103 +507,4 @@ typedef enum { // enable warnings again #pragma GCC diagnostic pop -// device paths -#define USBD_DEVICE_PATH "/dev/usb/usbd" -#define HUB_DEVICE_PATH "/dev/usb/hub" - -// hub rpc -#define HUB_ATTACH RPC_CUSTOM_START - -// usbd rpc -#define USBD_REGISTER_HANDLER RPC_CUSTOM_START -#define USBD_UNREGISTER_HANDLER USBD_REGISTER_HANDLER + 1 -#define USBD_GET_DESCRIPTOR USBD_UNREGISTER_HANDLER + 1 -#define USBD_GET_ENDPOINT USBD_GET_DESCRIPTOR + 1 -#define USBD_GET_INTERFACE USBD_GET_ENDPOINT + 1 -#define USBD_GET_DESCRIPTION USBD_GET_INTERFACE + 1 -#define USBD_CONTROL_MESSAGE USBD_GET_DESCRIPTION + 1 -#define USBD_ATTACH_DEVICE USBD_CONTROL_MESSAGE + 1 -#define USBD_GET_ROOTHUB USBD_ATTACH_DEVICE + 1 - -// generic usb rpc structures -typedef struct { - uint32_t parent_device_number; - uint32_t device_number; - uint32_t interface_number; -} usb_generic_attach_t; - -// usbd rpc structures -typedef struct { - libusb_interface_class_t type; - pid_t handler; -} usbd_register_device_handler_t; - -typedef struct { - libusb_interface_class_t type; - pid_t handler; -} usbd_unregister_device_handler_t; - -typedef struct { - size_t shm_id; -} usbd_get_descriptor_t; - -typedef struct { - uint32_t device_number; - libusb_descriptor_type_t type; - uint8_t index; - uint16_t lang_id; - size_t buffer_length; - size_t minimum_length; - uint8_t recipient; - uint8_t buffer[]; -} usb_descriptor_message_t; - -typedef struct { - // parameters - uint32_t device_number; - uint32_t interface_number; - uint32_t endpoint_number; - // space for return object - libusb_endpoint_descriptor_t descriptor; -} usbd_get_endpoint_t; - -typedef struct { - // parameters - uint32_t device_number; - uint32_t interface_number; - // space for return - libusb_interface_descriptor_t interface; -} usbd_get_interface_t; - -typedef struct { - uint32_t device_number; - char buffer[ 256 ]; -} usbd_get_description_t; - -typedef struct { - size_t shm_id; -} usbd_control_message_t; - -typedef struct { - uint32_t device_number; -} usbd_get_roothub_t; - -typedef struct { - uint32_t parent_number; - uint32_t port_number; - libusb_speed_t speed; -} usbd_attach_device_t; - -typedef struct { - uint32_t device_number; - libusb_transfer_t transfer; - libusb_direction_t direction; - size_t buffer_length; - libusb_device_request_t request; - size_t timeout; - uint32_t last_transfer; - libusb_transfer_error_t error; - uint8_t buffer[]; -} usb_control_message_t; - #endif diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h new file mode 100644 index 00000000..7e1cdc1f --- /dev/null +++ b/bolthur/server/libusbd.h @@ -0,0 +1,125 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIBUSBD_H +#define _LIBUSBD_H + +#include +#include "libusb.h" + +// device paths +#define USBD_DEVICE_PATH "/dev/usb/usbd" +#define HUB_DEVICE_PATH "/dev/usb/hub" + +// hub rpc +#define HUB_ATTACH RPC_CUSTOM_START + +// usbd rpc +#define USBD_REGISTER_HANDLER RPC_CUSTOM_START +#define USBD_UNREGISTER_HANDLER USBD_REGISTER_HANDLER + 1 +#define USBD_GET_DESCRIPTOR USBD_UNREGISTER_HANDLER + 1 +#define USBD_GET_ENDPOINT USBD_GET_DESCRIPTOR + 1 +#define USBD_GET_INTERFACE USBD_GET_ENDPOINT + 1 +#define USBD_GET_DESCRIPTION USBD_GET_INTERFACE + 1 +#define USBD_CONTROL_MESSAGE USBD_GET_DESCRIPTION + 1 +#define USBD_ATTACH_DEVICE USBD_CONTROL_MESSAGE + 1 +#define USBD_GET_ROOTHUB USBD_ATTACH_DEVICE + 1 + +// generic usb rpc structures +typedef struct { + uint32_t parent_device_number; + uint32_t device_number; + uint32_t interface_number; +} usb_generic_attach_t; + +// usbd rpc structures +typedef struct { + libusb_interface_class_t type; + pid_t handler; +} usbd_register_device_handler_t; + +typedef struct { + libusb_interface_class_t type; + pid_t handler; +} usbd_unregister_device_handler_t; + +typedef struct { + size_t shm_id; +} usbd_get_descriptor_t; + +typedef struct { + uint32_t device_number; + libusb_descriptor_type_t type; + uint8_t index; + uint16_t lang_id; + size_t buffer_length; + size_t minimum_length; + uint8_t recipient; + uint8_t buffer[]; +} usb_descriptor_message_t; + +typedef struct { + // parameters + uint32_t device_number; + uint32_t interface_number; + uint32_t endpoint_number; + // space for return object + libusb_endpoint_descriptor_t descriptor; +} usbd_get_endpoint_t; + +typedef struct { + // parameters + uint32_t device_number; + uint32_t interface_number; + // space for return + libusb_interface_descriptor_t interface; +} usbd_get_interface_t; + +typedef struct { + uint32_t device_number; + char buffer[ 256 ]; +} usbd_get_description_t; + +typedef struct { + size_t shm_id; +} usbd_control_message_t; + +typedef struct { + uint32_t device_number; +} usbd_get_roothub_t; + +typedef struct { + uint32_t parent_number; + uint32_t port_number; + libusb_speed_t speed; +} usbd_attach_device_t; + +typedef struct { + uint32_t device_number; + libusb_transfer_t transfer; + libusb_direction_t direction; + size_t buffer_length; + libusb_device_request_t request; + size_t timeout; + uint32_t last_transfer; + libusb_transfer_error_t error; + uint8_t buffer[]; +} usb_control_message_t; + +#endif //LIBUSBD_H diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 73f76afb..1756af10 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -25,6 +25,7 @@ #include "rpc.h" // library includes #include "../../../libhelper.h" +#include "../../../libusbd.h" #include "../../../../library/usb/usb.h" /** diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index cd911ddb..69c4695a 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -24,7 +24,7 @@ // local includes #include "../../hub.h" #include "../../rpc.h" -#include "../../../../../libusb.h" +#include "../../../../../libusbd.h" #include "../../../../../../library/usb/usb.h" static void custom_nanosleep( const struct timespec* rqtp ) { @@ -178,31 +178,6 @@ static int attach_hub_change_port_feature( &error, &last_transfer ); - /* - return usb_control_message( - dev, - ( libusb_pipe_address_t ){ - .type = LIBUSB_TRANSFER_CONTROL, - .speed = dev->speed, - .end_point = 0, - .device = ( uint8_t )dev->number, - .direction = LIBUSB_DIRECTION_OUT, - .max_size = usb_packet_size_from_number( - dev->descriptor.max_packet_size0 - ), - }, - NULL, - 0, - &( libusb_device_request_t ){ - .request = set - ? LIBUSB_DEVICE_REQUEST_SET_FEATURE - : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, - .type = 0x23, - .value = ( uint16_t )feature, - .index = port + 1, - }, - 10 /// FIXME: REPLACE WITH CONSTANT - );*/ } static int attach_hub_power_on( @@ -269,29 +244,7 @@ static int attach_hub_get_port_status( 10, /// FIXME: REPLACE WITH CONSTANT &error, &last_transfer - );/* - const int result = usb_control_message( - dev, - ( libusb_pipe_address_t ){ - .type = LIBUSB_TRANSFER_CONTROL, - .speed = dev->speed, - .end_point = 0, - .device = ( uint8_t )dev->number, - .direction = LIBUSB_DIRECTION_IN, - .max_size = usb_packet_size_from_number( - dev->descriptor.max_packet_size0 - ), - }, - &( ( libusb_hub_device_t* )dev->driver_data )->port_status[ port ], - sizeof( libusb_hub_port_full_status_t ), - &( libusb_device_request_t ){ - .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, - .type = 0xa3, - .index = port + 1, - .length = sizeof( libusb_hub_port_full_status_t ), - }, - 10 - );*/ + ); // handle result wrong if ( 0 != result ) { // debug output @@ -495,37 +448,6 @@ static int attach_hub_port_connection_changed( } // return success return 0; - - - /* - * - if ((result = UsbAllocateDevice(&data->Children[port])) != OK) { - LOGF("HUB: Could not allocate a new device entry for %s.Port%d.\n", UsbGetDescription(device), port + 1); - return result; - } - - if ((result = HubPortGetStatus(device, port)) != OK) { - LOGF("HUB: Hub failed to get status (3) for %s.Port%d.\n", UsbGetDescription(device), port + 1); - return result; - } - - LOG_DEBUGF("HUB: %s.Port%d Status %x:%x.\n", UsbGetDescription(device), port + 1, *(u16*)&portStatus->Status, *(u16*)&portStatus->Change); - - if (portStatus->Status.HighSpeedAttatched) data->Children[port]->Speed = High; - else if (portStatus->Status.LowSpeedAttatched) data->Children[port]->Speed = Low; - else data->Children[port]->Speed = Full; - data->Children[port]->Parent = device; - data->Children[port]->PortNumber = port; - if ((result = UsbAttachDevice(data->Children[port])) != OK) { - LOGF("HUB: Could not connect to new device in %s.Port%d. Disabling.\n", UsbGetDescription(device), port + 1); - UsbDeallocateDevice(data->Children[port]); - data->Children[port] = NULL; - if (HubChangePortFeature(device, FeatureEnable, port, false) != OK) { - LOGF("HUB: Failed to disable %s.Port%d.\n", UsbGetDescription(device), port + 1); - } - return result; - } - return OK;*/ } static int attach_hub_check_connection( @@ -595,12 +517,9 @@ static int attach_hub_check_connection( "%s. Port %d has been disabled but is connected. This can be caused by interference. Enabling it again\r\n", usb_get_description( device_number ), port + 1 ) #endif - }/* - // This may indicate EM interference. - if (!portStatus->Status.Enabled && portStatus->Status.Connected && data->Children[port] != NULL) { - LOGF("HUB: %s.Port%d has been disabled, but is connected. This can be cause by interference. Reenabling!\n", UsbGetDescription(device), port + 1); - HubPortConnectionChanged(device, port); - }*/ + // call connection changed + attach_hub_port_connection_changed( device_number, device_data, port ); + } } if ( port_status->status.suspended ) { STARTUP_PRINT( "SUSPENDED!\r\n" ) @@ -768,6 +687,7 @@ void rpc_hub_attach( if ( LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.power_switching_mode && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.power_switching_mode + && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != descriptor->attributes.power_switching_mode ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -789,6 +709,9 @@ void rpc_hub_attach( case LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL: STARTUP_PRINT( "Power mode is individual\r\n" ) break; + case LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING: + STARTUP_PRINT( "Power mode is no power switching supported\r\n" ) + break; } if ( descriptor->attributes.compound ) { STARTUP_PRINT( "Hub nature is compound\r\n" ) @@ -800,6 +723,7 @@ void rpc_hub_attach( if ( LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.over_current_protection && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.over_current_protection + && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != descriptor->attributes.over_current_protection ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -821,6 +745,9 @@ void rpc_hub_attach( case LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL: STARTUP_PRINT( "Hub over current protection is individual\r\n" ) break; + case LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING: + STARTUP_PRINT( "Hub has no over current protection\r\n" ) + break; } STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", descriptor->power_good_delay * 2 ) STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", descriptor->maximum_hub_power * 2 ) @@ -841,7 +768,7 @@ void rpc_hub_attach( return; } // cache status locally - libusb_hub_full_status_t* status = &hub->status; + const libusb_hub_full_status_t* status = &hub->status; // some debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Hub power: %s\r\n", diff --git a/bolthur/server/usb/device/hub/rpc/init.c b/bolthur/server/usb/device/hub/rpc/init.c index 89771035..019cb062 100644 --- a/bolthur/server/usb/device/hub/rpc/init.c +++ b/bolthur/server/usb/device/hub/rpc/init.c @@ -21,7 +21,7 @@ #include // local includes #include "../rpc.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn bool rpc_init(void) diff --git a/bolthur/server/usb/usbd/call.h b/bolthur/server/usb/usbd/call.h index 519b8ca4..91489458 100644 --- a/bolthur/server/usb/usbd/call.h +++ b/bolthur/server/usb/usbd/call.h @@ -20,7 +20,7 @@ #ifndef CALL_H #define CALL_H -#include "../../libusb.h" +#include "../../libusbd.h" #define CALL_ENABLE_DEBUG 1 diff --git a/bolthur/server/usb/usbd/rpc/attach/device.c b/bolthur/server/usb/usbd/rpc/attach/device.c index fbb4ec5a..fb0b7adc 100644 --- a/bolthur/server/usb/usbd/rpc/attach/device.c +++ b/bolthur/server/usb/usbd/rpc/attach/device.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_attach_device(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/control/message.c b/bolthur/server/usb/usbd/rpc/control/message.c index 8386b2e9..3daa050f 100644 --- a/bolthur/server/usb/usbd/rpc/control/message.c +++ b/bolthur/server/usb/usbd/rpc/control/message.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/get/description.c b/bolthur/server/usb/usbd/rpc/get/description.c index 356b9e5f..9c420ace 100644 --- a/bolthur/server/usb/usbd/rpc/get/description.c +++ b/bolthur/server/usb/usbd/rpc/get/description.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_get_description(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/get/descriptor.c b/bolthur/server/usb/usbd/rpc/get/descriptor.c index 6058d63d..3543a1fc 100644 --- a/bolthur/server/usb/usbd/rpc/get/descriptor.c +++ b/bolthur/server/usb/usbd/rpc/get/descriptor.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_get_descriptor(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/get/endpoint.c b/bolthur/server/usb/usbd/rpc/get/endpoint.c index 48ade779..e50273a1 100644 --- a/bolthur/server/usb/usbd/rpc/get/endpoint.c +++ b/bolthur/server/usb/usbd/rpc/get/endpoint.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_get_endpoint(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/get/interface.c b/bolthur/server/usb/usbd/rpc/get/interface.c index a1b94639..c770ba30 100644 --- a/bolthur/server/usb/usbd/rpc/get/interface.c +++ b/bolthur/server/usb/usbd/rpc/get/interface.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_get_endpoint(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/get/roothub.c b/bolthur/server/usb/usbd/rpc/get/roothub.c index 419ddcd2..5aea0e4f 100644 --- a/bolthur/server/usb/usbd/rpc/get/roothub.c +++ b/bolthur/server/usb/usbd/rpc/get/roothub.c @@ -25,7 +25,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_get_roothub(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/handler/register.c b/bolthur/server/usb/usbd/rpc/handler/register.c index d9716225..951d0bdc 100644 --- a/bolthur/server/usb/usbd/rpc/handler/register.c +++ b/bolthur/server/usb/usbd/rpc/handler/register.c @@ -24,7 +24,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/handler/unregister.c b/bolthur/server/usb/usbd/rpc/handler/unregister.c index a3a699a5..57e5ce44 100644 --- a/bolthur/server/usb/usbd/rpc/handler/unregister.c +++ b/bolthur/server/usb/usbd/rpc/handler/unregister.c @@ -24,7 +24,7 @@ #include "../../rpc.h" // driver includes #include "../../usbd.h" -#include "../../../../libusb.h" +#include "../../../../libusbd.h" /** * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c index 0d3d0075..d9e7db81 100644 --- a/bolthur/server/usb/usbd/rpc/init.c +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -21,7 +21,7 @@ #include // local includes #include "../rpc.h" -#include "../../../libusb.h" +#include "../../../libusbd.h" /** * @fn bool rpc_init(void) diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index 899d0df2..c2d604dd 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -31,7 +31,7 @@ // driver includes #include -#include "../../libusb.h" +#include "../../libusbd.h" #include "../../libhcd.h" /** @@ -930,6 +930,10 @@ const char* usbd_get_description( const libusb_device_t* dev ) { if ( dev->descriptor.vendor_id == 0x424 && dev->descriptor.product_id == 0xec00 ) { return "SMSC LAN9512"; } + // qemu cdc ethernet adapter + if ( dev->descriptor.vendor_id == 0x525 && dev->descriptor.product_id == 0xa4a2 ) { + return "QEMU CDC LAN"; + } return "Vendor specific"; // interfaces case LIBUSB_DEVICE_CLASS_IN_INTERFACE: diff --git a/bolthur/server/usb/usbd/usbd.h b/bolthur/server/usb/usbd/usbd.h index 426ee7ba..8be6ab15 100644 --- a/bolthur/server/usb/usbd/usbd.h +++ b/bolthur/server/usb/usbd/usbd.h @@ -20,7 +20,7 @@ #ifndef USBD_H #define USBD_H -#include "../../libusb.h" +#include "../../libusbd.h" #define USBD_ENABLE_DEBUG 1 From 42499fb923ea132b247d98c73ec92a35b2ff29a8 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 14:19:24 +0200 Subject: [PATCH 016/144] - Added generic rpc defines - Added hub rpc defines - Updated device_info of hub main used for registering path - Created empty rpc for check change, check connection, child detach, child reset and detach - Adjusted hub init to bind rpc handlers - Added new hid device acting as connector between usbd and keyboard and mouse --- bolthur/server/configure.ac | 1 + bolthur/server/libusbd.h | 10 ++++- bolthur/server/usb/device/hid/Makefile.am | 2 +- bolthur/server/usb/device/hid/hid/Makefile.am | 7 ++++ bolthur/server/usb/device/hid/hid/config.ini | 3 ++ bolthur/server/usb/device/hid/hid/main.c | 35 +++++++++++++++++ bolthur/server/usb/device/hub/Makefile.am | 6 +++ bolthur/server/usb/device/hub/main.c | 12 +++++- bolthur/server/usb/device/hub/rpc.h | 6 +++ .../usb/device/hub/rpc/hub/check/change.c | 37 ++++++++++++++++++ .../usb/device/hub/rpc/hub/check/connection.c | 37 ++++++++++++++++++ .../usb/device/hub/rpc/hub/child/detach.c | 37 ++++++++++++++++++ .../usb/device/hub/rpc/hub/child/reset.c | 37 ++++++++++++++++++ .../usb/device/hub/rpc/hub/deallocate.c | 37 ++++++++++++++++++ .../server/usb/device/hub/rpc/hub/detach.c | 37 ++++++++++++++++++ bolthur/server/usb/device/hub/rpc/init.c | 39 ++++++++++++++++++- config/ini/raspi/bcm2709/stage3.ini | 5 +++ 17 files changed, 343 insertions(+), 5 deletions(-) create mode 100644 bolthur/server/usb/device/hid/hid/Makefile.am create mode 100644 bolthur/server/usb/device/hid/hid/config.ini create mode 100644 bolthur/server/usb/device/hid/hid/main.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/check/change.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/check/connection.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/child/detach.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/child/reset.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/deallocate.c create mode 100644 bolthur/server/usb/device/hub/rpc/hub/detach.c diff --git a/bolthur/server/configure.ac b/bolthur/server/configure.ac index 4da4fde8..2621211a 100644 --- a/bolthur/server/configure.ac +++ b/bolthur/server/configure.ac @@ -162,6 +162,7 @@ AC_CONFIG_FILES([ usb/Makefile usb/device/Makefile usb/device/hid/Makefile + usb/device/hid/hid/Makefile usb/device/hid/keyboard/Makefile usb/device/hid/mouse/Makefile usb/device/hub/Makefile diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index 7e1cdc1f..fec537e3 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -27,8 +27,16 @@ #define USBD_DEVICE_PATH "/dev/usb/usbd" #define HUB_DEVICE_PATH "/dev/usb/hub" +// generic rpc +#define GENERIC_ATTACH RPC_CUSTOM_START +#define GENERIC_DETACH GENERIC_ATTACH + 1 +#define GENERIC_DEALLOCATE GENERIC_DETACH + 1 + // hub rpc -#define HUB_ATTACH RPC_CUSTOM_START +#define HUB_CHECK_CHANGE GENERIC_DEALLOCATE + 1 +#define HUB_CHILD_DETACH HUB_CHECK_CHANGE + 1 +#define HUB_CHILD_RESET HUB_CHILD_DETACH + 1 +#define HUB_CHECK_CONNECTION HUB_CHILD_RESET + 1 // usbd rpc #define USBD_REGISTER_HANDLER RPC_CUSTOM_START diff --git a/bolthur/server/usb/device/hid/Makefile.am b/bolthur/server/usb/device/hid/Makefile.am index 33ba9510..b6bf335f 100644 --- a/bolthur/server/usb/device/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/Makefile.am @@ -1,2 +1,2 @@ -SUBDIRS = keyboard mouse +SUBDIRS = hid keyboard mouse diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am new file mode 100644 index 00000000..29f7c79b --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -0,0 +1,7 @@ + +AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/hid\" + +bin_PROGRAMS = hid +hid_SOURCES = \ + main.c +hid_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/hid/config.ini b/bolthur/server/usb/device/hid/hid/config.ini new file mode 100644 index 00000000..fdb42676 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/config.ini @@ -0,0 +1,3 @@ +[general] +type=image_root +path=server/usb \ No newline at end of file diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c new file mode 100644 index 00000000..79db5a7c --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include + +/** + * @fn int main(int, char*[]) + * @brief main entry point + * + * @param argc + * @param argv + * @return + */ +int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { + // print something + STARTUP_PRINT( "usb hid hid processing!\r\n" ) + return -1; +} diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index 7cac3a61..da45479d 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -7,7 +7,13 @@ hub_DEPENDENCIES = \ hub_LDADD = \ ${abs_top_builddir}/../library/usb/libusb.la hub_SOURCES = \ + rpc/hub/check/change.c \ + rpc/hub/check/connection.c \ + rpc/hub/child/detach.c \ + rpc/hub/child/reset.c \ rpc/hub/attach.c \ + rpc/hub/deallocate.c \ + rpc/hub/detach.c \ rpc/init.c \ main.c hub_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 1756af10..fef82295 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -26,6 +26,8 @@ // library includes #include "../../../libhelper.h" #include "../../../libusbd.h" +#include "../../../libusbd.h" +#include "../../../libusbd.h" #include "../../../../library/usb/usb.h" /** @@ -67,9 +69,15 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // add device file STARTUP_PRINT( "Sending device to vfs\r\n" ) uint32_t device_info[] = { - HUB_ATTACH, + GENERIC_ATTACH, + GENERIC_DETACH, + GENERIC_DEALLOCATE, + HUB_CHECK_CHANGE, + HUB_CHILD_DETACH, + HUB_CHILD_RESET, + HUB_CHECK_CONNECTION, }; - if ( !dev_add_file( HUB_DEVICE_PATH, device_info, 1 ) ) { + if ( !dev_add_file( HUB_DEVICE_PATH, device_info, 7 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/hub/rpc.h b/bolthur/server/usb/device/hub/rpc.h index fa54a49e..9d764611 100644 --- a/bolthur/server/usb/device/hub/rpc.h +++ b/bolthur/server/usb/device/hub/rpc.h @@ -24,6 +24,12 @@ #include bool rpc_init( void ); +void rpc_hub_check_change( size_t, pid_t, size_t, size_t ); +void rpc_hub_check_connection( size_t, pid_t, size_t, size_t ); +void rpc_hub_child_detach( size_t, pid_t, size_t, size_t ); +void rpc_hub_child_reset( size_t, pid_t, size_t, size_t ); void rpc_hub_attach( size_t, pid_t, size_t, size_t ); +void rpc_hub_deallocate( size_t, pid_t, size_t, size_t ); +void rpc_hub_detach( size_t, pid_t, size_t, size_t ); #endif diff --git a/bolthur/server/usb/device/hub/rpc/hub/check/change.c b/bolthur/server/usb/device/hub/rpc/hub/check/change.c new file mode 100644 index 00000000..974356c3 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/check/change.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../../rpc.h" + +/** + * @fn void rpc_hub_check_change(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler check change + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_check_change( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/hub/check/connection.c b/bolthur/server/usb/device/hub/rpc/hub/check/connection.c new file mode 100644 index 00000000..b24b9c26 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/check/connection.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../../rpc.h" + +/** + * @fn void rpc_hub_check_connection(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler check connection + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_check_connection( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/hub/child/detach.c b/bolthur/server/usb/device/hub/rpc/hub/child/detach.c new file mode 100644 index 00000000..2df58a8b --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/child/detach.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../../rpc.h" + +/** + * @fn void rpc_hub_child_detach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler child detach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_child_detach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/hub/child/reset.c b/bolthur/server/usb/device/hub/rpc/hub/child/reset.c new file mode 100644 index 00000000..8a948056 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/child/reset.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../../rpc.h" + +/** + * @fn void rpc_hub_child_reset(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler child reset + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_child_reset( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/hub/deallocate.c b/bolthur/server/usb/device/hub/rpc/hub/deallocate.c new file mode 100644 index 00000000..d92fa77e --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/deallocate.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_hub_deallocate(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler deallocate + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_deallocate( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/hub/detach.c b/bolthur/server/usb/device/hub/rpc/hub/detach.c new file mode 100644 index 00000000..9c24ed20 --- /dev/null +++ b/bolthur/server/usb/device/hub/rpc/hub/detach.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_hub_detach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler detach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hub_detach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/rpc/init.c b/bolthur/server/usb/device/hub/rpc/init.c index 019cb062..438f0352 100644 --- a/bolthur/server/usb/device/hub/rpc/init.c +++ b/bolthur/server/usb/device/hub/rpc/init.c @@ -30,10 +30,47 @@ */ bool rpc_init( void ) { // register attach handler - bolthur_rpc_bind( HUB_ATTACH, rpc_hub_attach, true ); + bolthur_rpc_bind( GENERIC_ATTACH, rpc_hub_attach, true ); if ( errno ) { STARTUP_PRINT( "Unable to register attach handler!\r\n" ) return false; } + // register detach handler + bolthur_rpc_bind( GENERIC_DETACH, rpc_hub_detach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register detach handler!\r\n" ) + return false; + } + // register deallocate handler + bolthur_rpc_bind( GENERIC_DEALLOCATE, rpc_hub_deallocate, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register deallocate handler!\r\n" ) + return false; + } + // register check change handler + bolthur_rpc_bind( HUB_CHECK_CHANGE, rpc_hub_check_change, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register check change!\r\n" ) + return false; + } + // register child detach handler + bolthur_rpc_bind( HUB_CHILD_DETACH, rpc_hub_child_detach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register child detach!\r\n" ) + return false; + } + // register child reset handler + bolthur_rpc_bind( HUB_CHILD_RESET, rpc_hub_child_reset, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register child reset!\r\n" ) + return false; + } + // register check connection handler + bolthur_rpc_bind( HUB_CHECK_CONNECTION, rpc_hub_check_connection, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register check connection!\r\n" ) + return false; + } + // return success return true; } diff --git a/config/ini/raspi/bcm2709/stage3.ini b/config/ini/raspi/bcm2709/stage3.ini index dd616d8f..e5e38c70 100644 --- a/config/ini/raspi/bcm2709/stage3.ini +++ b/config/ini/raspi/bcm2709/stage3.ini @@ -8,6 +8,11 @@ path = /server/usb/hub device = /dev/usb/hub early = false +[hid] +path = /server/usb/hid +device = /dev/usb/hid +early = false + [keyboard] path = /server/usb/keyboard device = /dev/usb/keyboard From 32cc9fa7c44aec5b3792446614bd75778670529c Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 15:20:53 +0200 Subject: [PATCH 017/144] - Created plain hid rpc handlers - Reokaced device driver hub define by enum - Added hid, keyboard and mouse to device driver enum --- bolthur/server/libusb.h | 7 ++- bolthur/server/libusbd.h | 4 ++ bolthur/server/usb/device/hid/hid/Makefile.am | 6 ++ bolthur/server/usb/device/hid/hid/main.c | 8 +++ bolthur/server/usb/device/hid/hid/rpc.h | 33 ++++++++++ .../usb/device/hid/hid/rpc/handler/register.c | 42 +++++++++++++ .../device/hid/hid/rpc/handler/unregister.c | 42 +++++++++++++ .../usb/device/hid/hid/rpc/hid/attach.c | 43 +++++++++++++ .../usb/device/hid/hid/rpc/hid/deallocate.c | 37 +++++++++++ .../usb/device/hid/hid/rpc/hid/detach.c | 37 +++++++++++ bolthur/server/usb/device/hid/hid/rpc/init.c | 62 +++++++++++++++++++ 11 files changed, 320 insertions(+), 1 deletion(-) create mode 100644 bolthur/server/usb/device/hid/hid/rpc.h create mode 100644 bolthur/server/usb/device/hid/hid/rpc/handler/register.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/hid/attach.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/hid/deallocate.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/hid/detach.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/init.c diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 69b565fc..edcc6ba7 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -488,7 +488,12 @@ typedef enum { LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE = 20, } libusb_hub_port_feature_t; -#define DEVICE_DRIVER_HUB 0x48554230 +typedef enum { + DEVICE_DRIVER_HUB = 0x48554230, + DEVICE_DRIVER_HID = 0x48494430, + DEVICE_DRIVER_KEYBOARD = 0x4b424430, + DEVICE_DRIVER_MOUSE = 0x4b424431, +} device_driver_t; typedef struct { libusb_driver_data_header header; diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index fec537e3..9086d36a 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -32,6 +32,10 @@ #define GENERIC_DETACH GENERIC_ATTACH + 1 #define GENERIC_DEALLOCATE GENERIC_DETACH + 1 +// hid rpc +#define HID_REGISTER_HANDLER GENERIC_DEALLOCATE + 1 +#define HID_UNREGISTER_HANDLER HID_REGISTER_HANDLER + 1 + // hub rpc #define HUB_CHECK_CHANGE GENERIC_DEALLOCATE + 1 #define HUB_CHILD_DETACH HUB_CHECK_CHANGE + 1 diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index 29f7c79b..1b1a1bd5 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -3,5 +3,11 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/hid\" bin_PROGRAMS = hid hid_SOURCES = \ + rpc/handler/register.c \ + rpc/handler/unregister.c \ + rpc/hid/attach.c \ + rpc/hid/deallocate.c \ + rpc/hid/detach.c \ + rpc/init.c \ main.c hid_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c index 79db5a7c..c6035703 100644 --- a/bolthur/server/usb/device/hid/hid/main.c +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -19,6 +19,7 @@ #include #include +#include "rpc.h" /** * @fn int main(int, char*[]) @@ -29,6 +30,13 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); + return -1; + } + // print something STARTUP_PRINT( "usb hid hid processing!\r\n" ) return -1; diff --git a/bolthur/server/usb/device/hid/hid/rpc.h b/bolthur/server/usb/device/hid/hid/rpc.h new file mode 100644 index 00000000..d6f6a556 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc.h @@ -0,0 +1,33 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +void rpc_handler_register( size_t, pid_t, size_t, size_t ); +void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); +void rpc_hid_attach( size_t, pid_t, size_t, size_t ); +void rpc_hid_deallocate( size_t, pid_t, size_t, size_t ); +void rpc_hid_detach( size_t, pid_t, size_t, size_t ); +bool rpc_init( void ); + +#endif diff --git a/bolthur/server/usb/device/hid/hid/rpc/handler/register.c b/bolthur/server/usb/device/hid/hid/rpc/handler/register.c new file mode 100644 index 00000000..3fa12bd5 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/handler/register.c @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +// local includes +#include "../../rpc.h" + +/** + * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler for device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + * + * @todo request real origin via syscall and check compare it to handler + */ +void rpc_handler_register( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c b/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c new file mode 100644 index 00000000..1aa4afc3 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c @@ -0,0 +1,42 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +// local includes +#include "../../rpc.h" + +/** + * @fn void rpc_handler_unregister(size_t, pid_t, size_t, size_t) + * @brief Unregister rpc handler for device + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + * + * @todo request real origin via syscall and check compare it to handler + */ +void rpc_handler_unregister( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c new file mode 100644 index 00000000..5e566d04 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +#include "../../../../../../libusbd.h" +#include "../../../../../../../library/usb/usb.h" + +/** + * @fn void rpc_hid_attach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler attach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hid_attach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/deallocate.c b/bolthur/server/usb/device/hid/hid/rpc/hid/deallocate.c new file mode 100644 index 00000000..b2f5de39 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/deallocate.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_hid_deallocate(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler deallocate + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hid_deallocate( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/detach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/detach.c new file mode 100644 index 00000000..72c347e3 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/detach.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_hid_detach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler detach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_hid_detach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/init.c b/bolthur/server/usb/device/hid/hid/rpc/init.c new file mode 100644 index 00000000..cf35aecc --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/init.c @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include "../rpc.h" +#include "../../../../../libusbd.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + // register handler hid attach + bolthur_rpc_bind( GENERIC_ATTACH, rpc_hid_attach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register attach handler!\r\n" ) + return false; + } + // register handler detach + bolthur_rpc_bind( GENERIC_DETACH, rpc_hid_detach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register detach handler!\r\n" ) + return false; + } + // register handler deallocate + bolthur_rpc_bind( GENERIC_DEALLOCATE, rpc_hid_deallocate, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register deallocate handler!\r\n" ) + return false; + } + // register handler register + bolthur_rpc_bind( HID_REGISTER_HANDLER, rpc_handler_register, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register register device handler!\r\n" ) + return false; + } + // register handler unregister + bolthur_rpc_bind( HID_UNREGISTER_HANDLER, rpc_handler_unregister, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register unregister device handler!\r\n" ) + return false; + } + return true; +} From dbabeb57bac2500c4274183efeb2819c2377e3df Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 15:59:56 +0200 Subject: [PATCH 018/144] - Removed osproc and fixed warning in boot.nim - Extended image.nim to generate home user directory --- tool/util/boot.nim | 7 +++---- tool/util/image.nim | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tool/util/boot.nim b/tool/util/boot.nim index f0efdd64..b8501394 100644 --- a/tool/util/boot.nim +++ b/tool/util/boot.nim @@ -17,13 +17,12 @@ # along with bolthur/kernel. If not, see . # -import osproc import std/os import std/strutils import std/httpclient import zippy/tarballs -const firmware_version = "1.20250430" +const firmwareVersion = "1.20250430" proc onProgressChanged(total, progress, speed: BiggestInt): void = stdout.write "\rDownloaded ", progress, " of ", total, " - Current rate: ", speed div 1000, "kb/s" @@ -54,7 +53,7 @@ proc loadFirmwareToBoot*( firmwareType: string ): void = if not fileExists( joinPath( cachePath, "firmware.tar.gz" ) ): var client = newHttpClient() client.onProgressChanged = onProgressChanged - client.downloadFile( """https://github.com/raspberrypi/firmware/archive/refs/tags/""" & firmware_version & """.tar.gz""", joinPath( cachePath, "firmware.tar.gz" ) ) + client.downloadFile( """https://github.com/raspberrypi/firmware/archive/refs/tags/""" & firmwareVersion & """.tar.gz""", joinPath( cachePath, "firmware.tar.gz" ) ) stdout.write "\r\n" stdout.flushFile() # uncompress firmware if not existing @@ -62,7 +61,7 @@ proc loadFirmwareToBoot*( firmwareType: string ): void = # unzip firmware uncompressFirmware( joinPath( cachePath, "firmware.tar.gz" ), joinPath( cachePath, "firmware" ) ) # copy over to boot - let basePath = joinPath( cachePath, "firmware", """firmware-""" & firmware_version, "boot" ) + let basePath = joinPath( cachePath, "firmware", """firmware-""" & firmwareVersion, "boot" ) for file in walkDirRec( basePath, { pcFile, pcDir } ): let splitted = splitPath( file ) if splitted.tail.startsWith( "kernel" ): diff --git a/tool/util/image.nim b/tool/util/image.nim index 7381af50..a4acc689 100644 --- a/tool/util/image.nim +++ b/tool/util/image.nim @@ -107,11 +107,12 @@ proc createPlainImageFile*( imageType: string, rootPath: string ): void = let bootDirectoryPath: string = joinPath( basePath, "partition", "boot" ) let rootDirectoryPath: string = joinPath( basePath, "partition", "root" ) let rootEtcDirectoryPath: string = joinPath( rootDirectoryPath, "etc" ) - # create folder boot, root, ramdisk and etc in root image + # create folder boot, root, ramdisk, etc and home user in root image createDir( joinPath( rootDirectoryPath, "boot" ) ) createDir( joinPath( rootDirectoryPath, "ramdisk" ) ) createDir( rootEtcDirectoryPath ) createDir( joinPath( rootDirectoryPath, "root" ) ) + createDir( joinPath( rootDirectoryPath, "home", "user" ) ) # copy default root folder stuff let rootFileStuff: string = joinPath( getCurrentDir(), "file", imageType, "root" ) for file in walkDirRec( rootFileStuff, { pcFile } ): From e7b32f79bce3f11f12e809e9dd1406ec17413872 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 21:00:25 +0200 Subject: [PATCH 019/144] - Added no_sanitize kernel-address to __bootstrap - Added plain kasan library with minimum necessary functions doing nothing right now - Added sanitize option kernel-address when building with debug symbols --- bolthur/kernel/configure.ac | 3 +- bolthur/kernel/lib/Makefile.am | 13 +++---- bolthur/kernel/lib/kasan/Makefile.am | 4 ++ bolthur/kernel/lib/kasan/kasan.c | 50 +++++++++++++++++++++++++ bolthur/kernel/lib/kasan/kasan.h | 38 +++++++++++++++++++ bolthur/kernel/target/raspi/Makefile.am | 5 ++- build-aux/m4/flag.m4 | 2 +- 7 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 bolthur/kernel/lib/kasan/Makefile.am create mode 100644 bolthur/kernel/lib/kasan/kasan.c create mode 100644 bolthur/kernel/lib/kasan/kasan.h diff --git a/bolthur/kernel/configure.ac b/bolthur/kernel/configure.ac index d583d252..7446996a 100644 --- a/bolthur/kernel/configure.ac +++ b/bolthur/kernel/configure.ac @@ -322,7 +322,7 @@ AC_DEFINE_UNQUOTED( ) AC_DEFINE_UNQUOTED( [__bootstrap], - [__attribute__((__section__(".text.boot"),__optimize__("O0","no-stack-protector"), no_sanitize("undefined")))], + [__attribute__((__section__(".text.boot"),__optimize__("O0","no-stack-protector"), no_sanitize("undefined"), no_sanitize("kernel-address")))], [Bootstrap function] ) AC_DEFINE_UNQUOTED( @@ -345,6 +345,7 @@ AC_CONFIG_FILES([ lib/Makefile lib/atag/Makefile lib/libc/Makefile + lib/kasan/Makefile lib/tar/Makefile platform/Makefile platform/raspi/Makefile diff --git a/bolthur/kernel/lib/Makefile.am b/bolthur/kernel/lib/Makefile.am index 77934481..5d331047 100644 --- a/bolthur/kernel/lib/Makefile.am +++ b/bolthur/kernel/lib/Makefile.am @@ -1,11 +1,10 @@ -SUBDIRS = libc atag tar +SUBDIRS = libc atag kasan tar noinst_LTLIBRARIES = libubsan.la libssp.la libduplicate.la -libubsan_la_SOURCES = \ - ubsan.c -libssp_la_SOURCES = \ - ssp.c -libduplicate_la_SOURCES = \ - duplicate.c +libubsan_la_SOURCES = ubsan.c + +libssp_la_SOURCES = ssp.c + +libduplicate_la_SOURCES = duplicate.c diff --git a/bolthur/kernel/lib/kasan/Makefile.am b/bolthur/kernel/lib/kasan/Makefile.am new file mode 100644 index 00000000..dc8ffcf2 --- /dev/null +++ b/bolthur/kernel/lib/kasan/Makefile.am @@ -0,0 +1,4 @@ + +noinst_LTLIBRARIES = libkasan.la +libkasan_la_SOURCES = \ + kasan.c diff --git a/bolthur/kernel/lib/kasan/kasan.c b/bolthur/kernel/lib/kasan/kasan.c new file mode 100644 index 00000000..330e0d13 --- /dev/null +++ b/bolthur/kernel/lib/kasan/kasan.c @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "kasan.h" + +void __asan_handle_no_return( void ) { +} + +void __asan_store1_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_store4_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_store8_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_storeN_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_load1_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_load2_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_load4_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_load8_noabort( [[maybe_unused]] uintptr_t address ) { +} + +void __asan_loadN_noabort( [[maybe_unused]] uintptr_t address ) { +} diff --git a/bolthur/kernel/lib/kasan/kasan.h b/bolthur/kernel/lib/kasan/kasan.h new file mode 100644 index 00000000..de0b8552 --- /dev/null +++ b/bolthur/kernel/lib/kasan/kasan.h @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIB_KASAN_KASAN_H +#define _LIB_KASAN_KASAN_H + +#include + +void __asan_store1_noabort( uintptr_t ); +void __asan_store4_noabort( uintptr_t ); +void __asan_store8_noabort( uintptr_t ); +void __asan_storeN_noabort( uintptr_t ); + +void __asan_load1_noabort( uintptr_t ); +void __asan_load2_noabort( uintptr_t ); +void __asan_load4_noabort( uintptr_t ); +void __asan_load8_noabort( uintptr_t ); +void __asan_loadN_noabort( uintptr_t ); + +void __asan_handle_no_return( void ); + +#endif diff --git a/bolthur/kernel/target/raspi/Makefile.am b/bolthur/kernel/target/raspi/Makefile.am index 75f198de..cb1dbdc0 100644 --- a/bolthur/kernel/target/raspi/Makefile.am +++ b/bolthur/kernel/target/raspi/Makefile.am @@ -13,6 +13,7 @@ BUILT_SOURCES = \ ${abs_top_builddir}/lib/libduplicate.la \ ${abs_top_builddir}/lib/libssp.la \ ${abs_top_builddir}/lib/libubsan.la \ + ${abs_top_builddir}/lib/libasan.la \ libtarget.la \ kernel.elf \ kernel_qemu.elf @@ -30,6 +31,7 @@ libtarget_la_DEPENDENCIES = \ ${abs_top_builddir}/libkernel.la \ ${abs_top_builddir}/lib/atag/libatag.la \ ${abs_top_builddir}/lib/libc/libc.la \ + ${abs_top_builddir}/lib/kasan/libkasan.la \ ${abs_top_builddir}/lib/tar/libtar.la \ ${abs_top_builddir}/lib/libduplicate.la \ ${abs_top_builddir}/lib/libssp.la \ @@ -44,6 +46,7 @@ libtarget_la_LIBADD = \ ${abs_top_builddir}/libkernel.la \ ${abs_top_builddir}/lib/atag/libatag.la \ ${abs_top_builddir}/lib/libc/libc.la \ + ${abs_top_builddir}/lib/kasan/libkasan.la \ ${abs_top_builddir}/lib/tar/libtar.la \ ${abs_top_builddir}/lib/libduplicate.la \ ${abs_top_builddir}/lib/libssp.la \ @@ -60,7 +63,7 @@ kernel_elf_LDFLAGS = \ -all-static -Wl,-static \ -Wl,--start-group,-ltarget,-lgcc,-lfdt,--end-group kernel_elf_LDADD = -L./.libs - + # Normal kernel building for physical device kernel_qemu_elf_SOURCES = diff --git a/build-aux/m4/flag.m4 b/build-aux/m4/flag.m4 index a74df6f4..e14681bc 100644 --- a/build-aux/m4/flag.m4 +++ b/build-aux/m4/flag.m4 @@ -114,7 +114,7 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_FLAG], [ # debug parameter AS_IF([test "x$with_debug_symbols" == "xyes"], [ # debug symbols and sanitizer - AX_APPEND_COMPILE_FLAGS([-g -Og -fsanitize=undefined]) + AX_APPEND_COMPILE_FLAGS([-g -Og -fsanitize=undefined -fsanitize=kernel-address]) ]) # optimization level case "${with_optimization_level}" in From 843e3ed1f90b28bbefeaceb91547974c46995f85 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 22:00:27 +0200 Subject: [PATCH 020/144] - Added own list handling for kasan - Added own heap implementation for kasan --- bolthur/kernel/configure.ac | 2 +- bolthur/kernel/lib/kasan/Makefile.am | 4 +- bolthur/kernel/lib/kasan/heap.c | 201 +++++++++++++++++++++++++++ bolthur/kernel/lib/kasan/heap.h | 41 ++++++ bolthur/kernel/lib/kasan/list.c | 128 +++++++++++++++++ bolthur/kernel/lib/kasan/list.h | 39 ++++++ 6 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 bolthur/kernel/lib/kasan/heap.c create mode 100644 bolthur/kernel/lib/kasan/heap.h create mode 100644 bolthur/kernel/lib/kasan/list.c create mode 100644 bolthur/kernel/lib/kasan/list.h diff --git a/bolthur/kernel/configure.ac b/bolthur/kernel/configure.ac index 7446996a..bf3e63bd 100644 --- a/bolthur/kernel/configure.ac +++ b/bolthur/kernel/configure.ac @@ -312,7 +312,7 @@ AC_DEFINE_UNQUOTED( ) AC_DEFINE_UNQUOTED( [__no_sanitize], - [__attribute__((no_sanitize("undefined")))], + [__attribute__((no_sanitize("undefined"), no_sanitize("kernel-address")))], [disable undefined behaviour sanitization] ) AC_DEFINE_UNQUOTED( diff --git a/bolthur/kernel/lib/kasan/Makefile.am b/bolthur/kernel/lib/kasan/Makefile.am index dc8ffcf2..a1018fac 100644 --- a/bolthur/kernel/lib/kasan/Makefile.am +++ b/bolthur/kernel/lib/kasan/Makefile.am @@ -1,4 +1,6 @@ noinst_LTLIBRARIES = libkasan.la libkasan_la_SOURCES = \ - kasan.c + heap.c \ + kasan.c \ + list.c diff --git a/bolthur/kernel/lib/kasan/heap.c b/bolthur/kernel/lib/kasan/heap.c new file mode 100644 index 00000000..a231f87d --- /dev/null +++ b/bolthur/kernel/lib/kasan/heap.c @@ -0,0 +1,201 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "heap.h" +#include "list.h" + +/** + * @brief Memory start address + */ +static uint8_t* memory_start = NULL; + +/** + * @brief Memory size + */ +static size_t memory_size = 0; + +/** + * @brief Free list + */ +static kasan_list_t free_list[ HEAP_MEMORY_MAX_LEVELS ]; + +/** + * @fn static void* _kasan_heap_alloc(int32_t) + * @brief Helper to allocate block on index + * @param index + * @return + */ +static void* _kasan_heap_alloc( const int32_t index ) { + uint8_t* memory; + kasan_list_t* link; + // maximum levels reached + if ( index >= HEAP_MEMORY_MAX_LEVELS || 0 > index ) { + return NULL; + } + // handle list is empty + if ( kasan_list_empty( &free_list[ index ] ) ) { + // try to allocate from index above + memory = ( uint8_t* )_kasan_heap_alloc( index - 1 ); + // handle error + if ( ! memory ) { + return NULL; + } + // subtract offset + memory -= sizeof(memory_block_t); + // get size of blocks at level + const size_t size = HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( + index, memory_size ); + // split blocks into two + kasan_list_t* left = (kasan_list_t*)memory; + kasan_list_t* right = (kasan_list_t*)(memory + size); + // initialize both + kasan_list_init(left); + kasan_list_init(right); + // insert both to list + kasan_list_insert_tail( &free_list[ index ], left ); + kasan_list_insert_tail( &free_list[ index ], right ); + } + // get first item + link = kasan_list_shift( &free_list[ index ] ); + // set memory + memory = ( uint8_t* )link; + // populate block + memory_block_t* block = ( memory_block_t* )memory; + block->size = HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( index, memory_size ); + // return memory + return ( void* )( memory + sizeof( memory_block_t ) ); +} + +/** + * @fn static void _kasan_heap_free(void*, int32_t) + * @brief Internal heap free implementation + * @param mem + * @param level + */ +static void _kasan_heap_free( void* mem, const int32_t level ) { + // list entries for link and buddy link + kasan_list_t* link = NULL; + kasan_list_t* buddy_link = NULL; + // block to get real size + const memory_block_t* block = ( memory_block_t* )mem; + // cache block size + const size_t size = block->size; + // get memory index of pointer in level + const int32_t index = ( int32_t )HEAP_MEMORY_INDEX_OF_POINTER_IN_LEVEL( + mem, level, memory_start, memory_size ); + // variable for buddy address + uintptr_t buddy; + // determine buddy + if ( ! ( index & 1 ) ) { + buddy = ( uintptr_t )mem + size; + } else { + buddy = ( uintptr_t )mem - size; + } + // if not empty try to find buddy link + if ( ! kasan_list_empty( &free_list[ level ] ) ) { + // try to find buddy in free list of level + buddy_link = kasan_list_find( &free_list[ level ], buddy ); + } + link = ( kasan_list_t* )mem; + // initialize link + kasan_list_init( link ); + // insert into free list + kasan_list_insert_tail( &free_list[ level ], link ); + // handle buddy link found + if (buddy_link) { + // remove link and buddy link + kasan_list_remove( link ); + kasan_list_remove( buddy_link ); + // handle recursive free depending on index + if ( ! ( index & 1 ) ) { + _kasan_heap_free( link, level - 1 ); + } else { + _kasan_heap_free( buddy_link, level - 1 ); + } + } +} + +/** + * @fn int32_t kasan_heap_get_level(size_t) + * @brief Helper to get heap level by size + * @param size + * @return + */ +__no_sanitize int32_t kasan_heap_get_level( const size_t size ) { + int32_t level = 0; + size_t heap_size = memory_size; + while ( heap_size > size ) { + heap_size /= 2; + level++; + } + return level; +} + +/** + * @fn void kasan_heap_init(void*, size_t) + * @brief Initialize kasan shadow heap + */ +__no_sanitize void kasan_heap_init( void* mem, size_t size ) { + kasan_list_t* entry = ( kasan_list_t* )mem; + memory_start = mem; + memory_size = size; + // setup free list + for ( int i = 0; i < HEAP_MEMORY_MAX_LEVELS; i++ ) { + kasan_list_init( &free_list[ i ] ); + } + // setup list entry + kasan_list_init( entry ); + // insert on top level + kasan_list_insert_tail( &free_list[ 0 ], entry ); +} + +/** + * @fn void* kasan_heap_alloc(size_t) + * @brief Allocate something on kasan heap + * @param size + * @return + */ +__no_sanitize void* kasan_heap_alloc( size_t size ) { + // adjust size by memory block + size += sizeof( memory_block_t ); + // get level by size + const int32_t level = kasan_heap_get_level( size ); + // allocate and return result + return _kasan_heap_alloc( level ); +} + +/** + * @fn void kasan_heap_free(void*) + * @brief Free something on kasan heap + * @param mem + */ +__no_sanitize void kasan_heap_free( void* mem ) { + // convert to uint8_t + uint8_t* memory = ( uint8_t* )mem; + // assert memory within heap + if ( memory <= memory_start || memory >= memory_start + memory_size ) { + return; + } + // get management block + memory_block_t* block = ( memory_block_t* )( memory - sizeof( memory_block_t ) ); + // get level by size + const int32_t level = kasan_heap_get_level( block->size ); + // call recursive free + _kasan_heap_free( ( void* )block, level ); +} diff --git a/bolthur/kernel/lib/kasan/heap.h b/bolthur/kernel/lib/kasan/heap.h new file mode 100644 index 00000000..b79316cd --- /dev/null +++ b/bolthur/kernel/lib/kasan/heap.h @@ -0,0 +1,41 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIB_KASAN_HEAP_H +#define _LIB_KASAN_HEAP_H + +#include +#include + +#define HEAP_MEMORY_MAX_LEVELS 32 +#define HEAP_MEMORY_BLOCKS_PER_LEVEL( level ) ( 1 << ( level )) +#define HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( level, total_size ) ( ( total_size ) / ( 1 << ( level ) ) ) +#define HEAP_MEMORY_INDEX_OF_POINTER_IN_LEVEL( pointer, level, memory_start, total_size) \ + ( ( ( ( uintptr_t )pointer ) - ( ( uintptr_t )memory_start ) ) / ( HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( level, total_size ) ) ) + +typedef struct { + size_t size; +} memory_block_t; + +int32_t kasan_heap_get_level( size_t size ); +void kasan_heap_init( void*, size_t ); +void* kasan_heap_alloc( size_t ); +void kasan_heap_free( void* ptr ); + +#endif diff --git a/bolthur/kernel/lib/kasan/list.c b/bolthur/kernel/lib/kasan/list.c new file mode 100644 index 00000000..e67f9454 --- /dev/null +++ b/bolthur/kernel/lib/kasan/list.c @@ -0,0 +1,128 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "list.h" + +/** + * @fn void kasan_list_init(kasan_list_t*) + * @brief Initialize list + * @param list + */ +__no_sanitize void kasan_list_init( kasan_list_t* list ) { + list->next = NULL; + list->prev = NULL; +} + +/** + * @fn void kasan_list_insert_tail(kasan_list_t*, kasan_list_t*) + * @brief Insert into list at tail + * @param list + * @param item + */ +__no_sanitize void kasan_list_insert_tail( kasan_list_t* list, kasan_list_t* item ) { + // cache list in entry + kasan_list_t* entry = list; + // loop to end + while ( entry->next ) { + entry = entry->next; + } + // set next of entry + entry->next = item; + // set previous of item + item->prev = entry; + // set next of item + item->next = NULL; +} + +/** + * @fn bool kasan_list_empty(kasan_list_t*) + * @brief Wrapper to check if list is empty + * @param list + * @return + */ +__no_sanitize bool kasan_list_empty( kasan_list_t* list ) { + return !list->next && !list->prev; +} + +/** + * @fn kasan_list_t* kasan_list_shift(kasan_list_t*) + * @brief Wrapper to shift list item from list + * @param list + * @return + */ +__no_sanitize kasan_list_t* kasan_list_shift( kasan_list_t* list ) { + kasan_list_t* entry = list; + // handle next existing + if ( list->next ) { + // set previous of next + list->next->prev = entry->prev; + // overwrite list + list = list->next; + } + // unset entry next and previous + entry->next = NULL; + entry->prev = NULL; + // return shifted entry + return entry; +} + +/** + * @fn void kasan_list_remove(kasan_list_t*) + * @brief Remove item from list + * @param entry + */ +__no_sanitize void kasan_list_remove( kasan_list_t* entry ) { + // cache previous and next of entry + kasan_list_t* next = entry->next; + kasan_list_t* prev = entry->prev; + // handle previous existing + if ( prev ) { + prev->next = next; + } + // handle next existing + if ( next ) { + next->prev = prev; + } + // unset next and prev of entry + entry->next = NULL; + entry->prev = NULL; +} + +/** + * @fn kasan_list_t* kasan_list_find(kasan_list_t*, uintptr_t) + * @brief Find address in list + * @param list + * @param addr + * @return + */ +__no_sanitize kasan_list_t* kasan_list_find( kasan_list_t* list, uintptr_t addr ) { + kasan_list_t* entry = list; + // iterate through list + while ( entry ) { + // check for found + if ( addr == ( uintptr_t )entry ) { + return entry; + } + // go to next entry + entry = entry->next; + } + // nothing found, so return null + return NULL; +} diff --git a/bolthur/kernel/lib/kasan/list.h b/bolthur/kernel/lib/kasan/list.h new file mode 100644 index 00000000..b03eaa2f --- /dev/null +++ b/bolthur/kernel/lib/kasan/list.h @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _LIB_KASAN_LIST_H +#define _LIB_KASAN_LIST_H + +#include +#include + +typedef struct kasan_list kasan_list_t; +typedef struct kasan_list { + kasan_list_t* next; + kasan_list_t* prev; +} kasan_list_t; + +void kasan_list_init( kasan_list_t* ); +void kasan_list_insert_tail( kasan_list_t*, kasan_list_t* ); +bool kasan_list_empty( kasan_list_t* ); +kasan_list_t* kasan_list_shift( kasan_list_t* ); +void kasan_list_remove( kasan_list_t* ); +kasan_list_t* kasan_list_find( kasan_list_t*, uintptr_t ); + +#endif From f9ae90f230f46044894c5897422385fa9eb35b00 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 26 Jul 2025 22:33:22 +0200 Subject: [PATCH 021/144] - Removed v8 32 bit linker scripts - Added extra linker scripts when sanitizer is active with fixed sanitizer memory - Added new has sanitizer conditional to kernel configure.ac - Revised raspi Makefile.am to link kasan and ubsan only when sanitizer is set - Added switch between linker script with and without sanitizer depending on conditional --- bolthur/kernel/configure.ac | 2 + bolthur/kernel/target/raspi/Makefile.am | 36 +++++++-- ...l.v8.32.ld => physical.v6.32.sanitizer.ld} | 9 ++- .../target/raspi/physical.v7.32.sanitizer.ld | 81 +++++++++++++++++++ .../target/raspi/physical.v8.64.sanitizer.ld | 81 +++++++++++++++++++ ...{qemu.v8.32.ld => qemu.v6.32.sanitizer.ld} | 7 ++ .../target/raspi/qemu.v7.32.sanitizer.ld | 81 +++++++++++++++++++ .../target/raspi/qemu.v8.64.sanitizer.ld | 81 +++++++++++++++++++ 8 files changed, 369 insertions(+), 9 deletions(-) rename bolthur/kernel/target/raspi/{physical.v8.32.ld => physical.v6.32.sanitizer.ld} (90%) create mode 100644 bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld create mode 100644 bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld rename bolthur/kernel/target/raspi/{qemu.v8.32.ld => qemu.v6.32.sanitizer.ld} (91%) create mode 100644 bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld create mode 100644 bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld diff --git a/bolthur/kernel/configure.ac b/bolthur/kernel/configure.ac index bf3e63bd..b35db6aa 100644 --- a/bolthur/kernel/configure.ac +++ b/bolthur/kernel/configure.ac @@ -335,6 +335,8 @@ AC_DEFINE_UNQUOTED( AM_CONDITIONAL([IS32], [test $executable_format -eq 32]) AM_CONDITIONAL([IS64], [test $executable_format -eq 64]) +AM_CONDITIONAL([HAS_SANITIZER], [test "x$with_debug_symbols" == "xyes"]) + AC_CONFIG_FILES([ Makefile arch/Makefile diff --git a/bolthur/kernel/target/raspi/Makefile.am b/bolthur/kernel/target/raspi/Makefile.am index cb1dbdc0..6ca21d61 100644 --- a/bolthur/kernel/target/raspi/Makefile.am +++ b/bolthur/kernel/target/raspi/Makefile.am @@ -31,11 +31,9 @@ libtarget_la_DEPENDENCIES = \ ${abs_top_builddir}/libkernel.la \ ${abs_top_builddir}/lib/atag/libatag.la \ ${abs_top_builddir}/lib/libc/libc.la \ - ${abs_top_builddir}/lib/kasan/libkasan.la \ ${abs_top_builddir}/lib/tar/libtar.la \ ${abs_top_builddir}/lib/libduplicate.la \ - ${abs_top_builddir}/lib/libssp.la \ - ${abs_top_builddir}/lib/libubsan.la + ${abs_top_builddir}/lib/libssp.la libtarget_la_SOURCES = libtarget_la_LIBADD = \ ${abs_top_builddir}/../library/collection/list/liblist.la \ @@ -46,23 +44,38 @@ libtarget_la_LIBADD = \ ${abs_top_builddir}/libkernel.la \ ${abs_top_builddir}/lib/atag/libatag.la \ ${abs_top_builddir}/lib/libc/libc.la \ - ${abs_top_builddir}/lib/kasan/libkasan.la \ ${abs_top_builddir}/lib/tar/libtar.la \ ${abs_top_builddir}/lib/libduplicate.la \ - ${abs_top_builddir}/lib/libssp.la \ - ${abs_top_builddir}/lib/libubsan.la + ${abs_top_builddir}/lib/libssp.la libtarget_la_LDFLAGS = -all-static -Wl,-static +# sanitizer additions +if HAS_SANITIZER + libtarget_la_DEPENDENCIES += \ + ${abs_top_builddir}/lib/kasan/libkasan.la \ + ${abs_top_builddir}/lib/libubsan.la + libtarget_la_LIBADD += \ + ${abs_top_builddir}/lib/kasan/libkasan.la \ + ${abs_top_builddir}/lib/libubsan.la +endif # Normal kernel building for physical device kernel_elf_SOURCES = kernel_elf_DEPENDENCIES = libtarget.la kernel_elf_LDFLAGS = \ -Wl,-L,${top_srcdir}/target \ - -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.ld \ -Wl,-Map,${output_map} \ -all-static -Wl,-static \ -Wl,--start-group,-ltarget,-lgcc,-lfdt,--end-group kernel_elf_LDADD = -L./.libs +# sanitizer additions +if HAS_SANITIZER + kernel_elf_LDFLAGS += \ + -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.sanitizer.ld +else + kernel_elf_LDFLAGS += \ + -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.ld +endif + # Normal kernel building for physical device @@ -70,11 +83,18 @@ kernel_qemu_elf_SOURCES = kernel_qemu_elf_DEPENDENCIES = libtarget.la kernel_qemu_elf_LDFLAGS = \ -Wl,-L,${top_srcdir}/target \ - -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.ld \ -Wl,-Map,${output_map_qemu} \ -all-static -Wl,-static \ -Wl,--start-group,-ltarget,-lgcc,-lfdt,--end-group kernel_qemu_elf_LDADD = -L./.libs +# sanitizer additions +if HAS_SANITIZER + kernel_qemu_elf_LDFLAGS += \ + -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.sanitizer.ld +else + kernel_qemu_elf_LDFLAGS += \ + -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.ld +endif EXTRA_PROGRAMS = kernel.img kernel7.img kernel8.img kernel_qemu.img kernel7_qemu.img kernel8_qemu.img kernel_img_DEPENDENCIES = kernel.elf diff --git a/bolthur/kernel/target/raspi/physical.v8.32.ld b/bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld similarity index 90% rename from bolthur/kernel/target/raspi/physical.v8.32.ld rename to bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld index 624ba7b2..2161e571 100644 --- a/bolthur/kernel/target/raspi/physical.v8.32.ld +++ b/bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld @@ -22,7 +22,7 @@ OUTPUT_ARCH( arm ) ENTRY( startup ) -KERNEL_LMA = 0x80000; +KERNEL_LMA = 0x8000; KERNEL_OFFSET = 0xC0000000; SECTIONS { @@ -67,6 +67,13 @@ SECTIONS { . += 0x100000; __initial_heap_end = .; + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + __bss_end = .; } diff --git a/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld b/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld new file mode 100644 index 00000000..2161e571 --- /dev/null +++ b/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +OUTPUT_FORMAT( elf32-littlearm ) +OUTPUT_ARCH( arm ) + +ENTRY( startup ) + +KERNEL_LMA = 0x8000; +KERNEL_OFFSET = 0xC0000000; + +SECTIONS { + . = KERNEL_LMA; + __kernel_start = . + KERNEL_OFFSET; + + /* boot kernel sections */ + .text.boot : ALIGN( 4K ) { + *( .text.boot ) + } + + .data.boot : ALIGN( 4K ) { + *( .data.boot ) + } + + . += KERNEL_OFFSET; + + /* higher half kernel sections */ + .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { + *( .text ) + } + + .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { + *( .rodata ) + } + + .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { + __data_start = .; + *( .data ) + __data_end = .; + } + + .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { + __bss_start = .; + *( COMMON ) + *( .bss ) + + /* align to 4k */ + . = ALIGN( 4K ); + /* 1MB for initial heap */ + __initial_heap_start = .; + . += 0x100000; + __initial_heap_end = .; + + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + + __bss_end = .; + } + + __kernel_end = .; +} diff --git a/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld b/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld new file mode 100644 index 00000000..86599a9b --- /dev/null +++ b/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +OUTPUT_FORMAT( elf64-littleaarch64 ) +OUTPUT_ARCH( arm ) + +ENTRY( startup ) + +KERNEL_LMA = 0x80000; +KERNEL_OFFSET = 0xffffffff80000000; + +SECTIONS { + . = KERNEL_LMA; + __kernel_start = . + KERNEL_OFFSET; + + /* boot kernel sections */ + .text.boot : ALIGN( 4K ) { + *( .text.boot ) + } + + .data.boot : ALIGN( 4K ) { + *( .data.boot ) + } + + . += KERNEL_OFFSET; + + /* higher half kernel sections */ + .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { + *( .text ) + } + + .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { + *( .rodata ) + } + + .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { + __data_start = .; + *( .data ) + __data_end = .; + } + + .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { + __bss_start = .; + *( COMMON ) + *( .bss ) + + /* align to 4k */ + . = ALIGN( 4K ); + /* 1MB for initial heap */ + __initial_heap_start = .; + . += 0x100000; + __initial_heap_end = .; + + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + + __bss_end = .; + } + + __kernel_end = .; +} diff --git a/bolthur/kernel/target/raspi/qemu.v8.32.ld b/bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld similarity index 91% rename from bolthur/kernel/target/raspi/qemu.v8.32.ld rename to bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld index 1cb7a53c..b5a818da 100644 --- a/bolthur/kernel/target/raspi/qemu.v8.32.ld +++ b/bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld @@ -67,6 +67,13 @@ SECTIONS { . += 0x100000; __initial_heap_end = .; + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + __bss_end = .; } diff --git a/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld b/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld new file mode 100644 index 00000000..b5a818da --- /dev/null +++ b/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +OUTPUT_FORMAT( elf32-littlearm ) +OUTPUT_ARCH( arm ) + +ENTRY( startup ) + +KERNEL_LMA = 0x10000; +KERNEL_OFFSET = 0xC0000000; + +SECTIONS { + . = KERNEL_LMA; + __kernel_start = . + KERNEL_OFFSET; + + /* boot kernel sections */ + .text.boot : ALIGN( 4K ) { + *( .text.boot ) + } + + .data.boot : ALIGN( 4K ) { + *( .data.boot ) + } + + . += KERNEL_OFFSET; + + /* higher half kernel sections */ + .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { + *( .text ) + } + + .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { + *( .rodata ) + } + + .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { + __data_start = .; + *( .data ) + __data_end = .; + } + + .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { + __bss_start = .; + *( COMMON ) + *( .bss ) + + /* align to 4k */ + . = ALIGN( 4K ); + /* 1MB for initial heap */ + __initial_heap_start = .; + . += 0x100000; + __initial_heap_end = .; + + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + + __bss_end = .; + } + + __kernel_end = .; +} diff --git a/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld b/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld new file mode 100644 index 00000000..6d896077 --- /dev/null +++ b/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld @@ -0,0 +1,81 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +OUTPUT_FORMAT( elf64-littleaarch64 ) +OUTPUT_ARCH( arm ) + +ENTRY( startup ) + +KERNEL_LMA = 0x10000; +KERNEL_OFFSET = 0xffffffff80000000; + +SECTIONS { + . = KERNEL_LMA; + __kernel_start = . + KERNEL_OFFSET; + + /* boot kernel sections */ + .text.boot : ALIGN( 4K ) { + *( .text.boot ) + } + + .data.boot : ALIGN( 4K ) { + *( .data.boot ) + } + + . += KERNEL_OFFSET; + + /* higher half kernel sections */ + .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { + *( .text ) + } + + .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { + *( .rodata ) + } + + .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { + __data_start = .; + *( .data ) + __data_end = .; + } + + .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { + __bss_start = .; + *( COMMON ) + *( .bss ) + + /* align to 4k */ + . = ALIGN( 4K ); + /* 1MB for initial heap */ + __initial_heap_start = .; + . += 0x100000; + __initial_heap_end = .; + + /* align to 4k */ + . = ALIGN( 4K ); + /* 16MB for sanitizer heap */ + __sanitizer_heap_start = .; + . += 0x1000000; + __sanitizer_heap_end = .; + + __bss_end = .; + } + + __kernel_end = .; +} From 75ea3705aa9976c16a62b0830028ee01e9a0fb7c Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sun, 27 Jul 2025 01:11:36 +0200 Subject: [PATCH 022/144] - Fixed .gdbinit-qemu and .gdbinit-qemu-user loading wrong dtb files - Added __bootstrap to firmware_startup_init and initrd_startup_init - Adjusted map temporary to perform startup map when virtual memory wasn't yet initialized - Removed unnecessary kasan heap and list code - Removed also unnecessary sanitizer linker scripts --- .gdbinit-qemu | 2 +- .gdbinit-qemu-user | 2 +- bolthur/kernel/arch/arm/firmware.c | 2 +- bolthur/kernel/arch/arm/initrd.c | 2 +- bolthur/kernel/arch/arm/v7/mm/virt/long.c | 9 +- bolthur/kernel/arch/arm/v7/mm/virt/short.c | 5 + bolthur/kernel/lib/kasan/Makefile.am | 4 +- bolthur/kernel/lib/kasan/heap.c | 201 ------------------ bolthur/kernel/lib/kasan/heap.h | 41 ---- bolthur/kernel/lib/kasan/list.c | 128 ----------- bolthur/kernel/lib/kasan/list.h | 39 ---- bolthur/kernel/target/raspi/Makefile.am | 20 +- .../target/raspi/physical.v6.32.sanitizer.ld | 81 ------- .../target/raspi/physical.v7.32.sanitizer.ld | 81 ------- .../target/raspi/physical.v8.64.sanitizer.ld | 81 ------- .../target/raspi/qemu.v6.32.sanitizer.ld | 81 ------- .../target/raspi/qemu.v7.32.sanitizer.ld | 81 ------- .../target/raspi/qemu.v8.64.sanitizer.ld | 81 ------- build-aux/m4/host.m4 | 5 + thirdparty/dlmalloc/dlmalloc.c | 1 + 20 files changed, 25 insertions(+), 922 deletions(-) delete mode 100644 bolthur/kernel/lib/kasan/heap.c delete mode 100644 bolthur/kernel/lib/kasan/heap.h delete mode 100644 bolthur/kernel/lib/kasan/list.c delete mode 100644 bolthur/kernel/lib/kasan/list.h delete mode 100644 bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld delete mode 100644 bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld delete mode 100644 bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld delete mode 100644 bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld delete mode 100644 bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld delete mode 100644 bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld diff --git a/.gdbinit-qemu b/.gdbinit-qemu index ae7aa5e9..febecfe4 100644 --- a/.gdbinit-qemu +++ b/.gdbinit-qemu @@ -2,7 +2,7 @@ set architecture armv7 file build/bolthur/kernel/target/raspi/kernel7_qemu.sym #add-symbol-file build/bolthur/server/platform/raspi/iomem/iomem -target remote | qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -kernel build/bolthur/kernel/target/raspi/kernel7_qemu.img -initrd build-aux/platform/raspi/initrd -dtb config/dts/raspi/bcm2836-raspi-2-b.dtb -drive file=build-aux/platform/raspi/sdcard.img,format=raw -gdb stdio -S +target remote | qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -kernel build/bolthur/kernel/target/raspi/kernel7_qemu.img -initrd build-aux/platform/raspi/initrd -dtb config/dts/raspi/bcm2709-raspi-2-b.dtb -drive file=build-aux/platform/raspi/sdcard.img,format=raw -gdb stdio -S display /10i $pc #break _vector_undefined_instruction_handler #c diff --git a/.gdbinit-qemu-user b/.gdbinit-qemu-user index 891123da..ae92645b 100644 --- a/.gdbinit-qemu-user +++ b/.gdbinit-qemu-user @@ -1,5 +1,5 @@ set architecture armv7 file build/bolthur/server/fs/ext/ext -target remote | qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -kernel ./build/bolthur/kernel/target/raspi/kernel7_qemu.img -initrd build-aux/platform/raspi/initrd -dtb config/dts/raspi/bcm2836-raspi-2-b.dtb -drive file=build-aux/platform/raspi/sdcard2.img,format=raw -append "coherent_pool=1M snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 snd_bcm2835.enable_headphones=1 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=1024 bcm2708_fb.fbswap=1 vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 root=/dev/storage/sd1 rootfstype=ext2" -gdb stdio -S +target remote | qemu-system-arm -M raspi2b -cpu cortex-a7 -m 1G -no-reboot -kernel ./build/bolthur/kernel/target/raspi/kernel7_qemu.img -initrd build-aux/platform/raspi/initrd -dtb config/dts/raspi/bcm2709-raspi-2-b.dtb -drive file=build-aux/platform/raspi/sdcard2.img,format=raw -append "coherent_pool=1M snd_bcm2835.enable_compat_alsa=0 snd_bcm2835.enable_hdmi=1 snd_bcm2835.enable_headphones=1 bcm2708_fb.fbwidth=1280 bcm2708_fb.fbheight=1024 bcm2708_fb.fbswap=1 vc_mem.mem_base=0x3ec00000 vc_mem.mem_size=0x40000000 root=/dev/storage/sd1 rootfstype=ext2" -gdb stdio -S display /10i $pc diff --git a/bolthur/kernel/arch/arm/firmware.c b/bolthur/kernel/arch/arm/firmware.c index 539d24f2..d5f652c0 100644 --- a/bolthur/kernel/arch/arm/firmware.c +++ b/bolthur/kernel/arch/arm/firmware.c @@ -29,7 +29,7 @@ * @fn void firmware_startup_init(void) * @brief Handle firmware information related startup init */ -void firmware_startup_init( void ) { +__bootstrap void firmware_startup_init( void ) { // transfer to uintptr_t uintptr_t atag_fdt = ( uintptr_t )firmware_info.atag_fdt; // first mapping before access diff --git a/bolthur/kernel/arch/arm/initrd.c b/bolthur/kernel/arch/arm/initrd.c index 82f35488..9f26e42b 100644 --- a/bolthur/kernel/arch/arm/initrd.c +++ b/bolthur/kernel/arch/arm/initrd.c @@ -27,7 +27,7 @@ /** * @brief Prepare for initrd usage */ -void initrd_startup_init( void ) { +__bootstrap void initrd_startup_init( void ) { // transfer to uintptr_t uintptr_t atag_fdt = ( uintptr_t )firmware_info.atag_fdt; diff --git a/bolthur/kernel/arch/arm/v7/mm/virt/long.c b/bolthur/kernel/arch/arm/v7/mm/virt/long.c index c0f78d21..9bceabc9 100644 --- a/bolthur/kernel/arch/arm/v7/mm/virt/long.c +++ b/bolthur/kernel/arch/arm/v7/mm/virt/long.c @@ -217,6 +217,11 @@ static uintptr_t map_temporary( uint64_t start, size_t size ) { // stop here if not initialized if ( true != virt_init_get() ) { + // map initially + for ( size_t i = ( size_t )start; i < start + size; i += PAGE_SIZE ) { + virt_startup_map( i, i ); + } + // return start address return ( uintptr_t )start; } @@ -484,14 +489,14 @@ static uint64_t get_temporary_mapping( uintptr_t addr ) { * @param table set to non zero for destroying a table * @return address to new table or 0 if it was used for free up */ -static uint64_t get_new_table( uint64_t table ) { +static uint64_t get_new_table( const uint64_t table ) { // handle free only if set if ( 0 != table ) { phys_free_page( table ); return 0; } // get new page - uint64_t addr = phys_find_free_page( PAGE_SIZE, PHYS_MEMORY_TYPE_NORMAL ); + const uint64_t addr = phys_find_free_page( PAGE_SIZE, PHYS_MEMORY_TYPE_NORMAL ); // debug output #if defined( PRINT_MM_VIRT ) DEBUG_OUTPUT( "addr = %#"PRIx64"\r\n", addr ) diff --git a/bolthur/kernel/arch/arm/v7/mm/virt/short.c b/bolthur/kernel/arch/arm/v7/mm/virt/short.c index aad9780c..0957bbb2 100644 --- a/bolthur/kernel/arch/arm/v7/mm/virt/short.c +++ b/bolthur/kernel/arch/arm/v7/mm/virt/short.c @@ -191,6 +191,11 @@ static uintptr_t map_temporary( uintptr_t start, size_t size ) { // stop here if not initialized if ( true != virt_init_get() ) { + // map initially + for ( size_t i = start; i < start + size; i += PAGE_SIZE ) { + virt_startup_map( i, i ); + } + // return start address return start; } diff --git a/bolthur/kernel/lib/kasan/Makefile.am b/bolthur/kernel/lib/kasan/Makefile.am index a1018fac..dc8ffcf2 100644 --- a/bolthur/kernel/lib/kasan/Makefile.am +++ b/bolthur/kernel/lib/kasan/Makefile.am @@ -1,6 +1,4 @@ noinst_LTLIBRARIES = libkasan.la libkasan_la_SOURCES = \ - heap.c \ - kasan.c \ - list.c + kasan.c diff --git a/bolthur/kernel/lib/kasan/heap.c b/bolthur/kernel/lib/kasan/heap.c deleted file mode 100644 index a231f87d..00000000 --- a/bolthur/kernel/lib/kasan/heap.c +++ /dev/null @@ -1,201 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -#include "heap.h" -#include "list.h" - -/** - * @brief Memory start address - */ -static uint8_t* memory_start = NULL; - -/** - * @brief Memory size - */ -static size_t memory_size = 0; - -/** - * @brief Free list - */ -static kasan_list_t free_list[ HEAP_MEMORY_MAX_LEVELS ]; - -/** - * @fn static void* _kasan_heap_alloc(int32_t) - * @brief Helper to allocate block on index - * @param index - * @return - */ -static void* _kasan_heap_alloc( const int32_t index ) { - uint8_t* memory; - kasan_list_t* link; - // maximum levels reached - if ( index >= HEAP_MEMORY_MAX_LEVELS || 0 > index ) { - return NULL; - } - // handle list is empty - if ( kasan_list_empty( &free_list[ index ] ) ) { - // try to allocate from index above - memory = ( uint8_t* )_kasan_heap_alloc( index - 1 ); - // handle error - if ( ! memory ) { - return NULL; - } - // subtract offset - memory -= sizeof(memory_block_t); - // get size of blocks at level - const size_t size = HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( - index, memory_size ); - // split blocks into two - kasan_list_t* left = (kasan_list_t*)memory; - kasan_list_t* right = (kasan_list_t*)(memory + size); - // initialize both - kasan_list_init(left); - kasan_list_init(right); - // insert both to list - kasan_list_insert_tail( &free_list[ index ], left ); - kasan_list_insert_tail( &free_list[ index ], right ); - } - // get first item - link = kasan_list_shift( &free_list[ index ] ); - // set memory - memory = ( uint8_t* )link; - // populate block - memory_block_t* block = ( memory_block_t* )memory; - block->size = HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( index, memory_size ); - // return memory - return ( void* )( memory + sizeof( memory_block_t ) ); -} - -/** - * @fn static void _kasan_heap_free(void*, int32_t) - * @brief Internal heap free implementation - * @param mem - * @param level - */ -static void _kasan_heap_free( void* mem, const int32_t level ) { - // list entries for link and buddy link - kasan_list_t* link = NULL; - kasan_list_t* buddy_link = NULL; - // block to get real size - const memory_block_t* block = ( memory_block_t* )mem; - // cache block size - const size_t size = block->size; - // get memory index of pointer in level - const int32_t index = ( int32_t )HEAP_MEMORY_INDEX_OF_POINTER_IN_LEVEL( - mem, level, memory_start, memory_size ); - // variable for buddy address - uintptr_t buddy; - // determine buddy - if ( ! ( index & 1 ) ) { - buddy = ( uintptr_t )mem + size; - } else { - buddy = ( uintptr_t )mem - size; - } - // if not empty try to find buddy link - if ( ! kasan_list_empty( &free_list[ level ] ) ) { - // try to find buddy in free list of level - buddy_link = kasan_list_find( &free_list[ level ], buddy ); - } - link = ( kasan_list_t* )mem; - // initialize link - kasan_list_init( link ); - // insert into free list - kasan_list_insert_tail( &free_list[ level ], link ); - // handle buddy link found - if (buddy_link) { - // remove link and buddy link - kasan_list_remove( link ); - kasan_list_remove( buddy_link ); - // handle recursive free depending on index - if ( ! ( index & 1 ) ) { - _kasan_heap_free( link, level - 1 ); - } else { - _kasan_heap_free( buddy_link, level - 1 ); - } - } -} - -/** - * @fn int32_t kasan_heap_get_level(size_t) - * @brief Helper to get heap level by size - * @param size - * @return - */ -__no_sanitize int32_t kasan_heap_get_level( const size_t size ) { - int32_t level = 0; - size_t heap_size = memory_size; - while ( heap_size > size ) { - heap_size /= 2; - level++; - } - return level; -} - -/** - * @fn void kasan_heap_init(void*, size_t) - * @brief Initialize kasan shadow heap - */ -__no_sanitize void kasan_heap_init( void* mem, size_t size ) { - kasan_list_t* entry = ( kasan_list_t* )mem; - memory_start = mem; - memory_size = size; - // setup free list - for ( int i = 0; i < HEAP_MEMORY_MAX_LEVELS; i++ ) { - kasan_list_init( &free_list[ i ] ); - } - // setup list entry - kasan_list_init( entry ); - // insert on top level - kasan_list_insert_tail( &free_list[ 0 ], entry ); -} - -/** - * @fn void* kasan_heap_alloc(size_t) - * @brief Allocate something on kasan heap - * @param size - * @return - */ -__no_sanitize void* kasan_heap_alloc( size_t size ) { - // adjust size by memory block - size += sizeof( memory_block_t ); - // get level by size - const int32_t level = kasan_heap_get_level( size ); - // allocate and return result - return _kasan_heap_alloc( level ); -} - -/** - * @fn void kasan_heap_free(void*) - * @brief Free something on kasan heap - * @param mem - */ -__no_sanitize void kasan_heap_free( void* mem ) { - // convert to uint8_t - uint8_t* memory = ( uint8_t* )mem; - // assert memory within heap - if ( memory <= memory_start || memory >= memory_start + memory_size ) { - return; - } - // get management block - memory_block_t* block = ( memory_block_t* )( memory - sizeof( memory_block_t ) ); - // get level by size - const int32_t level = kasan_heap_get_level( block->size ); - // call recursive free - _kasan_heap_free( ( void* )block, level ); -} diff --git a/bolthur/kernel/lib/kasan/heap.h b/bolthur/kernel/lib/kasan/heap.h deleted file mode 100644 index b79316cd..00000000 --- a/bolthur/kernel/lib/kasan/heap.h +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -#ifndef _LIB_KASAN_HEAP_H -#define _LIB_KASAN_HEAP_H - -#include -#include - -#define HEAP_MEMORY_MAX_LEVELS 32 -#define HEAP_MEMORY_BLOCKS_PER_LEVEL( level ) ( 1 << ( level )) -#define HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( level, total_size ) ( ( total_size ) / ( 1 << ( level ) ) ) -#define HEAP_MEMORY_INDEX_OF_POINTER_IN_LEVEL( pointer, level, memory_start, total_size) \ - ( ( ( ( uintptr_t )pointer ) - ( ( uintptr_t )memory_start ) ) / ( HEAP_MEMORY_SIZE_OF_BLOCKS_AT_LEVEL( level, total_size ) ) ) - -typedef struct { - size_t size; -} memory_block_t; - -int32_t kasan_heap_get_level( size_t size ); -void kasan_heap_init( void*, size_t ); -void* kasan_heap_alloc( size_t ); -void kasan_heap_free( void* ptr ); - -#endif diff --git a/bolthur/kernel/lib/kasan/list.c b/bolthur/kernel/lib/kasan/list.c deleted file mode 100644 index e67f9454..00000000 --- a/bolthur/kernel/lib/kasan/list.c +++ /dev/null @@ -1,128 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -#include -#include "list.h" - -/** - * @fn void kasan_list_init(kasan_list_t*) - * @brief Initialize list - * @param list - */ -__no_sanitize void kasan_list_init( kasan_list_t* list ) { - list->next = NULL; - list->prev = NULL; -} - -/** - * @fn void kasan_list_insert_tail(kasan_list_t*, kasan_list_t*) - * @brief Insert into list at tail - * @param list - * @param item - */ -__no_sanitize void kasan_list_insert_tail( kasan_list_t* list, kasan_list_t* item ) { - // cache list in entry - kasan_list_t* entry = list; - // loop to end - while ( entry->next ) { - entry = entry->next; - } - // set next of entry - entry->next = item; - // set previous of item - item->prev = entry; - // set next of item - item->next = NULL; -} - -/** - * @fn bool kasan_list_empty(kasan_list_t*) - * @brief Wrapper to check if list is empty - * @param list - * @return - */ -__no_sanitize bool kasan_list_empty( kasan_list_t* list ) { - return !list->next && !list->prev; -} - -/** - * @fn kasan_list_t* kasan_list_shift(kasan_list_t*) - * @brief Wrapper to shift list item from list - * @param list - * @return - */ -__no_sanitize kasan_list_t* kasan_list_shift( kasan_list_t* list ) { - kasan_list_t* entry = list; - // handle next existing - if ( list->next ) { - // set previous of next - list->next->prev = entry->prev; - // overwrite list - list = list->next; - } - // unset entry next and previous - entry->next = NULL; - entry->prev = NULL; - // return shifted entry - return entry; -} - -/** - * @fn void kasan_list_remove(kasan_list_t*) - * @brief Remove item from list - * @param entry - */ -__no_sanitize void kasan_list_remove( kasan_list_t* entry ) { - // cache previous and next of entry - kasan_list_t* next = entry->next; - kasan_list_t* prev = entry->prev; - // handle previous existing - if ( prev ) { - prev->next = next; - } - // handle next existing - if ( next ) { - next->prev = prev; - } - // unset next and prev of entry - entry->next = NULL; - entry->prev = NULL; -} - -/** - * @fn kasan_list_t* kasan_list_find(kasan_list_t*, uintptr_t) - * @brief Find address in list - * @param list - * @param addr - * @return - */ -__no_sanitize kasan_list_t* kasan_list_find( kasan_list_t* list, uintptr_t addr ) { - kasan_list_t* entry = list; - // iterate through list - while ( entry ) { - // check for found - if ( addr == ( uintptr_t )entry ) { - return entry; - } - // go to next entry - entry = entry->next; - } - // nothing found, so return null - return NULL; -} diff --git a/bolthur/kernel/lib/kasan/list.h b/bolthur/kernel/lib/kasan/list.h deleted file mode 100644 index b03eaa2f..00000000 --- a/bolthur/kernel/lib/kasan/list.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -#ifndef _LIB_KASAN_LIST_H -#define _LIB_KASAN_LIST_H - -#include -#include - -typedef struct kasan_list kasan_list_t; -typedef struct kasan_list { - kasan_list_t* next; - kasan_list_t* prev; -} kasan_list_t; - -void kasan_list_init( kasan_list_t* ); -void kasan_list_insert_tail( kasan_list_t*, kasan_list_t* ); -bool kasan_list_empty( kasan_list_t* ); -kasan_list_t* kasan_list_shift( kasan_list_t* ); -void kasan_list_remove( kasan_list_t* ); -kasan_list_t* kasan_list_find( kasan_list_t*, uintptr_t ); - -#endif diff --git a/bolthur/kernel/target/raspi/Makefile.am b/bolthur/kernel/target/raspi/Makefile.am index 6ca21d61..89312ac5 100644 --- a/bolthur/kernel/target/raspi/Makefile.am +++ b/bolthur/kernel/target/raspi/Makefile.am @@ -63,38 +63,22 @@ kernel_elf_SOURCES = kernel_elf_DEPENDENCIES = libtarget.la kernel_elf_LDFLAGS = \ -Wl,-L,${top_srcdir}/target \ + -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.ld \ -Wl,-Map,${output_map} \ -all-static -Wl,-static \ -Wl,--start-group,-ltarget,-lgcc,-lfdt,--end-group kernel_elf_LDADD = -L./.libs -# sanitizer additions -if HAS_SANITIZER - kernel_elf_LDFLAGS += \ - -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.sanitizer.ld -else - kernel_elf_LDFLAGS += \ - -Wl,-T,${top_srcdir}/target/raspi/physical.${subarch_subdir}.${executable_format}.ld -endif - - # Normal kernel building for physical device kernel_qemu_elf_SOURCES = kernel_qemu_elf_DEPENDENCIES = libtarget.la kernel_qemu_elf_LDFLAGS = \ -Wl,-L,${top_srcdir}/target \ + -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.ld \ -Wl,-Map,${output_map_qemu} \ -all-static -Wl,-static \ -Wl,--start-group,-ltarget,-lgcc,-lfdt,--end-group kernel_qemu_elf_LDADD = -L./.libs -# sanitizer additions -if HAS_SANITIZER - kernel_qemu_elf_LDFLAGS += \ - -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.sanitizer.ld -else - kernel_qemu_elf_LDFLAGS += \ - -Wl,-T,${top_srcdir}/target/raspi/qemu.${subarch_subdir}.${executable_format}.ld -endif EXTRA_PROGRAMS = kernel.img kernel7.img kernel8.img kernel_qemu.img kernel7_qemu.img kernel8_qemu.img kernel_img_DEPENDENCIES = kernel.elf diff --git a/bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld b/bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld deleted file mode 100644 index 2161e571..00000000 --- a/bolthur/kernel/target/raspi/physical.v6.32.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf32-littlearm ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x8000; -KERNEL_OFFSET = 0xC0000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld b/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld deleted file mode 100644 index 2161e571..00000000 --- a/bolthur/kernel/target/raspi/physical.v7.32.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf32-littlearm ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x8000; -KERNEL_OFFSET = 0xC0000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld b/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld deleted file mode 100644 index 86599a9b..00000000 --- a/bolthur/kernel/target/raspi/physical.v8.64.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf64-littleaarch64 ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x80000; -KERNEL_OFFSET = 0xffffffff80000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld b/bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld deleted file mode 100644 index b5a818da..00000000 --- a/bolthur/kernel/target/raspi/qemu.v6.32.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf32-littlearm ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x10000; -KERNEL_OFFSET = 0xC0000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld b/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld deleted file mode 100644 index b5a818da..00000000 --- a/bolthur/kernel/target/raspi/qemu.v7.32.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf32-littlearm ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x10000; -KERNEL_OFFSET = 0xC0000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld b/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld deleted file mode 100644 index 6d896077..00000000 --- a/bolthur/kernel/target/raspi/qemu.v8.64.sanitizer.ld +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright (C) 2018 - 2025 bolthur project. - * - * This file is part of bolthur/kernel. - * - * bolthur/kernel is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * bolthur/kernel is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with bolthur/kernel. If not, see . - */ - -OUTPUT_FORMAT( elf64-littleaarch64 ) -OUTPUT_ARCH( arm ) - -ENTRY( startup ) - -KERNEL_LMA = 0x10000; -KERNEL_OFFSET = 0xffffffff80000000; - -SECTIONS { - . = KERNEL_LMA; - __kernel_start = . + KERNEL_OFFSET; - - /* boot kernel sections */ - .text.boot : ALIGN( 4K ) { - *( .text.boot ) - } - - .data.boot : ALIGN( 4K ) { - *( .data.boot ) - } - - . += KERNEL_OFFSET; - - /* higher half kernel sections */ - .text ALIGN( 4K ) : AT( ADDR( .text ) - KERNEL_OFFSET ) { - *( .text ) - } - - .rodata ALIGN( 4K ) : AT( ADDR( .rodata ) - KERNEL_OFFSET ) { - *( .rodata ) - } - - .data ALIGN( 4K ) : AT( ADDR( .data ) - KERNEL_OFFSET ) { - __data_start = .; - *( .data ) - __data_end = .; - } - - .bss ALIGN( 4K ) : AT( ADDR( .bss ) - KERNEL_OFFSET ) { - __bss_start = .; - *( COMMON ) - *( .bss ) - - /* align to 4k */ - . = ALIGN( 4K ); - /* 1MB for initial heap */ - __initial_heap_start = .; - . += 0x100000; - __initial_heap_end = .; - - /* align to 4k */ - . = ALIGN( 4K ); - /* 16MB for sanitizer heap */ - __sanitizer_heap_start = .; - . += 0x1000000; - __sanitizer_heap_end = .; - - __bss_end = .; - } - - __kernel_end = .; -} diff --git a/build-aux/m4/host.m4 b/build-aux/m4/host.m4 index bb161536..cd9ea708 100644 --- a/build-aux/m4/host.m4 +++ b/build-aux/m4/host.m4 @@ -5,6 +5,7 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_HOST], [ AH_TEMPLATE([ELF64], [Define to 1 for 64 bit ELF targets]) AH_TEMPLATE([IS_HIGHER_HALF], [Define to 1 when kernel is higher half]) AH_TEMPLATE([REMOTE_DEBUG], [Define to 1 to enable remote debugging]) + AH_TEMPLATE([HAS_SANITIZER], [Define to 1 to enable compile in of sanitizer stuff]) # Output related define templates AH_TEMPLATE([OUTPUT_ENABLE], [Define to 1 to enable kernel print]) AH_TEMPLATE([PRINT_MM_PHYS], [Define to 1 to enable output of physical memory manager]) @@ -120,6 +121,10 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_HOST], [ AC_DEFINE([PRINT_SSP],[1]) ]) + AS_IF([test "x$with_debug_symbols" == "xyes"], [ + AC_DEFINE([HAS_SANITIZER],[1]) + ]) + case "${host_cpu}" in arm) arch_subdir=arm diff --git a/thirdparty/dlmalloc/dlmalloc.c b/thirdparty/dlmalloc/dlmalloc.c index 00fb19a8..aaa64632 100644 --- a/thirdparty/dlmalloc/dlmalloc.c +++ b/thirdparty/dlmalloc/dlmalloc.c @@ -534,6 +534,7 @@ MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP #include #include "../../bolthur/kernel/mm/heap.h" #include "../../bolthur/kernel/panic.h" +#include "../../bolthur/kernel/lib/string.h" // configuration part for kernel #define LACKS_UNISTD_H #define LACKS_FCNTL_H From daee5dabb876712696b1ed7b91ac9e47ee5e7e9b Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Mon, 28 Jul 2025 19:33:39 +0200 Subject: [PATCH 023/144] - Prefixed dlmalloc functions with no sanitize for kernel-address - Updated raspi memory map by area for kasan - Implemented kasan functions for detecting issues - Remove automatic memset from alloc and added memset where it was missing - Added new helper to get heap state - Added init of kasan within normal heap init - Added call to kasan poison shadow when extending the heap - Fixed kasan read error within strlen implementation - Fixed memset issue and added call to kasan_check_memory - Added call to kasan_check_memory within memcpy - Revised aligned_alloc and free to call kasan hooks if activated - Integrated unmap of initrd in kernel after control has been passed to boot - Introduced new helper to get file handler of a server --- bolthur/kernel/arch/arm/initrd.c | 11 +- bolthur/kernel/arch/arm/v7/mm/virt.c | 8 +- bolthur/kernel/arch/arm/v7/mm/virt/long.c | 6 +- bolthur/kernel/arch/arm/v7/mm/virt/short.c | 6 +- bolthur/kernel/initrd.c | 30 ++- bolthur/kernel/initrd.h | 1 + bolthur/kernel/lib/kasan/Makefile.am | 5 +- bolthur/kernel/lib/kasan/aligned_alloc.c | 57 +++++ bolthur/kernel/lib/kasan/free.c | 46 ++++ bolthur/kernel/lib/kasan/kasan.c | 199 +++++++++++++++++- bolthur/kernel/lib/kasan/kasan.h | 53 ++++- bolthur/kernel/lib/kasan/print.c | 82 ++++++++ .../kernel/lib/libc/stdlib/aligned_alloc.c | 13 +- bolthur/kernel/lib/libc/stdlib/free.c | 11 +- bolthur/kernel/lib/libc/string/memcpy.c | 8 + bolthur/kernel/lib/libc/string/memset.c | 18 +- bolthur/kernel/lib/libc/string/strlen.c | 50 +---- bolthur/kernel/main.c | 8 +- bolthur/kernel/mm/heap.c | 26 ++- bolthur/kernel/mm/heap.h | 14 +- bolthur/kernel/mm/virt.c | 8 +- .../kernel/platform/raspi/mailbox/property.c | 1 + bolthur/kernel/platform/raspi/mm/phys.c | 2 + bolthur/kernel/syscall/print.c | 6 +- bolthur/kernel/syscall/rpc.c | 4 +- bolthur/server/libhelper.h | 65 ++++++ bolthur/server/usb/device/hub/global.h | 27 +++ bolthur/server/usb/device/hub/main.c | 12 ++ .../server/usb/device/hub/rpc/hub/attach.c | 13 ++ build-aux/platform/raspi/memory_map.md | 3 +- thirdparty/dlmalloc/dlmalloc.c | 80 +++---- 31 files changed, 733 insertions(+), 140 deletions(-) create mode 100644 bolthur/kernel/lib/kasan/aligned_alloc.c create mode 100644 bolthur/kernel/lib/kasan/free.c create mode 100644 bolthur/kernel/lib/kasan/print.c create mode 100644 bolthur/server/usb/device/hub/global.h diff --git a/bolthur/kernel/arch/arm/initrd.c b/bolthur/kernel/arch/arm/initrd.c index 9f26e42b..d071f4c6 100644 --- a/bolthur/kernel/arch/arm/initrd.c +++ b/bolthur/kernel/arch/arm/initrd.c @@ -29,11 +29,11 @@ */ __bootstrap void initrd_startup_init( void ) { // transfer to uintptr_t - uintptr_t atag_fdt = ( uintptr_t )firmware_info.atag_fdt; + const uintptr_t atag_fdt = ( uintptr_t )firmware_info.atag_fdt; // handle atag if ( atag_check( atag_fdt ) ) { - atag_t* ramdisk = atag_find( ( atag_t* )atag_fdt, ATAG_TAG_INITRD2 ); + const atag_t* ramdisk = atag_find( ( atag_t* )atag_fdt, ATAG_TAG_INITRD2 ); if ( ramdisk ) { initrd_set_start_address( ramdisk->initrd.start ); initrd_set_size( ramdisk->initrd.size ); @@ -46,14 +46,13 @@ __bootstrap void initrd_startup_init( void ) { } } else if ( 0 == fdt_check_header( ( void* )atag_fdt ) ) { // get chosen node - int32_t node = fdt_path_offset( ( void* )atag_fdt, "/chosen" ); - uint32_t* prop; + const int32_t node = fdt_path_offset( ( void* )atag_fdt, "/chosen" ); int len; uintptr_t initrd_start = 0; uintptr_t initrd_end = 0; // try to get property initrd start - prop = ( uint32_t* )fdt_getprop( + const uint32_t* prop = ( uint32_t* )fdt_getprop( ( void* )atag_fdt, node, "linux,initrd-start", @@ -93,7 +92,7 @@ __bootstrap void initrd_startup_init( void ) { // map initrd if ( initrd_exist() ) { uintptr_t start = initrd_get_start_address(); - uintptr_t end = initrd_get_end_address(); + const uintptr_t end = initrd_get_end_address(); // map 1:1 while ( start < end ) { virt_startup_map( start, start ); diff --git a/bolthur/kernel/arch/arm/v7/mm/virt.c b/bolthur/kernel/arch/arm/v7/mm/virt.c index 40dc02b3..b89e2688 100644 --- a/bolthur/kernel/arch/arm/v7/mm/virt.c +++ b/bolthur/kernel/arch/arm/v7/mm/virt.c @@ -278,8 +278,8 @@ virt_context_t* virt_create_context( virt_context_type_t type ) { return NULL; } // allocate bitmap for lookup - uintptr_t min = virt_get_context_min_address( context ); - uintptr_t max = virt_get_context_max_address( context ); + const uintptr_t min = virt_get_context_min_address( context ); + const uintptr_t max = virt_get_context_max_address( context ); context->bitmap_length = ( max - min ) / PAGE_SIZE / VIRT_PAGE_PER_ENTRY; context->bitmap = aligned_alloc( sizeof( *( context->bitmap ) ), @@ -300,8 +300,8 @@ virt_context_t* virt_create_context( virt_context_type_t type ) { return NULL; } // allocate bitmap for lookup - uintptr_t min = virt_get_context_min_address( context ); - uintptr_t max = virt_get_context_max_address( context ); + const uintptr_t min = virt_get_context_min_address( context ); + const uintptr_t max = virt_get_context_max_address( context ); context->bitmap_length = ( max - min ) / PAGE_SIZE / VIRT_PAGE_PER_ENTRY; context->bitmap = aligned_alloc( sizeof( *( context->bitmap ) ), diff --git a/bolthur/kernel/arch/arm/v7/mm/virt/long.c b/bolthur/kernel/arch/arm/v7/mm/virt/long.c index 9bceabc9..d34e874d 100644 --- a/bolthur/kernel/arch/arm/v7/mm/virt/long.c +++ b/bolthur/kernel/arch/arm/v7/mm/virt/long.c @@ -1154,11 +1154,13 @@ virt_context_t* v7_long_create_context( virt_context_type_t type ) { // reserve space for context uint64_t ctx; if ( !virt_init_get() ) { - ctx = ( uintptr_t )aligned_alloc( PAGE_SIZE, sizeof( ld_global_page_directory_t ) ); + void* tmp = aligned_alloc( PAGE_SIZE, sizeof( ld_global_page_directory_t ) ); // handle error - if ( ! ctx ) { + if ( ! tmp ) { return NULL; } + memset( tmp, 0, sizeof( ld_global_page_directory_t ) ); + ctx = ( uintptr_t )tmp; ctx = VIRT_2_PHYS( ctx ); } else { ctx = phys_find_free_page_range( PAGE_SIZE, sizeof( ld_global_page_directory_t ), PHYS_MEMORY_TYPE_NORMAL ); diff --git a/bolthur/kernel/arch/arm/v7/mm/virt/short.c b/bolthur/kernel/arch/arm/v7/mm/virt/short.c index 0957bbb2..be88a3ab 100644 --- a/bolthur/kernel/arch/arm/v7/mm/virt/short.c +++ b/bolthur/kernel/arch/arm/v7/mm/virt/short.c @@ -1179,11 +1179,13 @@ virt_context_t* v7_short_create_context( virt_context_type_t type ) { // reserve space for context uint64_t phys; if ( !virt_init_get() ) { - phys = ( uintptr_t )aligned_alloc( alignment, size ); + void* tmp = aligned_alloc( alignment, size ); // handle error - if ( ! phys ) { + if ( ! tmp ) { return NULL; } + memset( tmp, 0, size ); + phys = ( uintptr_t )tmp; phys = VIRT_2_PHYS( phys ); } else { phys = phys_find_free_page_range( alignment, size, PHYS_MEMORY_TYPE_NORMAL ); diff --git a/bolthur/kernel/initrd.c b/bolthur/kernel/initrd.c index a2d4e23f..75141921 100644 --- a/bolthur/kernel/initrd.c +++ b/bolthur/kernel/initrd.c @@ -21,6 +21,10 @@ #include #include "initrd.h" +#include "../application/usr/lib/ld-bolthur/tmp/_dl-int.h" +#include "lib/assert.h" +#include "mm/virt.h" + /** * @brief internal initrd load address */ @@ -45,7 +49,7 @@ uintptr_t initrd_get_start_address( void ) { * * @param address */ -void initrd_set_start_address( uintptr_t address ) { +void initrd_set_start_address( const uintptr_t address ) { initrd_address = address; } @@ -72,7 +76,7 @@ size_t initrd_get_size( void ) { * * @param size */ -void initrd_set_size( size_t size ) { +void initrd_set_size( const size_t size ) { initrd_size = size; } @@ -85,3 +89,25 @@ void initrd_set_size( size_t size ) { bool initrd_exist( void ) { return 0 < initrd_size; } + +/** + * @fn void initrd_unmap(void) + * @brief Helper to unmap initrd + */ +void initrd_unmap( void ) { + // skip in case no initrd is existing + if ( ! initrd_exist() ) { + return; + } + // get start address rounded up since it may be mapped directly behind + // the kernel + uintptr_t start = ROUND_UP_TO_FULL_PAGE( initrd_address ); + const uintptr_t end = initrd_address + initrd_size; + while ( start < end ) { + // unmap with free of physical space + assert( virt_unmap_address( virt_current_kernel_context, start, true ) ); + // get to next page + start += PAGE_SIZE; + } + /// FIXME: IMPLEMENT +} diff --git a/bolthur/kernel/initrd.h b/bolthur/kernel/initrd.h index 62cbb052..1a300a63 100644 --- a/bolthur/kernel/initrd.h +++ b/bolthur/kernel/initrd.h @@ -31,5 +31,6 @@ size_t initrd_get_size( void ); void initrd_set_size( size_t ); bool initrd_exist( void ); void initrd_startup_init( void ); +void initrd_unmap( void ); #endif diff --git a/bolthur/kernel/lib/kasan/Makefile.am b/bolthur/kernel/lib/kasan/Makefile.am index dc8ffcf2..dd817d9e 100644 --- a/bolthur/kernel/lib/kasan/Makefile.am +++ b/bolthur/kernel/lib/kasan/Makefile.am @@ -1,4 +1,7 @@ noinst_LTLIBRARIES = libkasan.la libkasan_la_SOURCES = \ - kasan.c + aligned_alloc.c \ + free.c \ + kasan.c \ + print.c diff --git a/bolthur/kernel/lib/kasan/aligned_alloc.c b/bolthur/kernel/lib/kasan/aligned_alloc.c new file mode 100644 index 00000000..a856f966 --- /dev/null +++ b/bolthur/kernel/lib/kasan/aligned_alloc.c @@ -0,0 +1,57 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include + +#include "kasan.h" +#include "../../panic.h" +#include "../../debug/debug.h" + +/** + * @fn void* kasan_aligned_alloc_hook(size_t, size_t) + * @brief Aligned allocation hook + * @param alignment + * @param size + * @return + */ +__no_sanitize void* kasan_aligned_alloc_hook( const size_t alignment, const size_t size ) { + // for early heap skip asan + if ( heap_get_state() == HEAP_INIT_EARLY ) { + return heap_allocate( alignment, size ); + } + kasan_heap_header_t* kasan_heap_header = NULL; + const size_t aligned_size = ( size + KASAN_SHADOW_MASK ) & ~KASAN_SHADOW_MASK; + const size_t total_size = aligned_size + KASAN_HEAP_HEAD_REDZONE_SIZE + + KASAN_HEAP_TAIL_REDZONE_SIZE; + //DEBUG_OUTPUT( "Allocating %#zx, original size %#zx\r\n", total_size, size ) + // allocate some block + void* ptr = heap_allocate( alignment, total_size ); + if ( ! ptr ) { + return NULL; + } + //DEBUG_OUTPUT( "ptr = %#"PRIxPTR"\r\n", ( uintptr_t )ptr ) + // populate kasan information + kasan_heap_header = ( kasan_heap_header_t* )ptr; + kasan_heap_header->aligned_size = aligned_size; + + kasan_unpoison_shadow( ( uintptr_t )ptr + KASAN_HEAP_HEAD_REDZONE_SIZE, size ); + kasan_poison_shadow( ( uintptr_t )ptr, KASAN_HEAP_HEAD_REDZONE_SIZE, ASAN_SHADOW_HEAP_HEAD_REDZONE_MAGIC, false ); + kasan_poison_shadow(( uintptr_t )ptr + KASAN_HEAP_HEAD_REDZONE_SIZE + aligned_size, KASAN_HEAP_TAIL_REDZONE_SIZE, ASAN_SHADOW_HEAP_TAIL_REDZONE_MAGIC, false ); + return ( void* )( ( uintptr_t )ptr + KASAN_HEAP_HEAD_REDZONE_SIZE ); +} diff --git a/bolthur/kernel/lib/kasan/free.c b/bolthur/kernel/lib/kasan/free.c new file mode 100644 index 00000000..81e013c1 --- /dev/null +++ b/bolthur/kernel/lib/kasan/free.c @@ -0,0 +1,46 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "kasan.h" + +/** + * @fn void kasan_free_hook(void*) + * @brief kasan free hook + * @param ptr + */ +__no_sanitize void kasan_free_hook( void* ptr ) { + // handle invalid address + if ( ! ptr ) { + return; + } + // for early heap skip asan + if ( heap_get_state() == HEAP_INIT_EARLY ) { + heap_free( ptr ); + return; + } + // translate to kasan heap header + kasan_heap_header_t* kasan_heap_header = ( kasan_heap_header_t* )( + ( uintptr_t )ptr - KASAN_HEAP_HEAD_REDZONE_SIZE ); + // extract aligned size + const size_t aligned_size = kasan_heap_header->aligned_size; + // free address + heap_free( kasan_heap_header ); + // poison shadow + kasan_poison_shadow( ( uintptr_t )ptr, aligned_size, ASAN_SHADOW_HEAP_FREE_MAGIC, false ); +} diff --git a/bolthur/kernel/lib/kasan/kasan.c b/bolthur/kernel/lib/kasan/kasan.c index 330e0d13..a1f736f6 100644 --- a/bolthur/kernel/lib/kasan/kasan.c +++ b/bolthur/kernel/lib/kasan/kasan.c @@ -17,34 +17,213 @@ * along with bolthur/kernel. If not, see . */ +#include #include "kasan.h" +#include "../assert.h" +#include "../string.h" +#include "../../../application/usr/lib/ld-bolthur/tmp/_dl-int.h" +#include "../../debug/debug.h" +#include "../../mm/virt.h" -void __asan_handle_no_return( void ) { +/** + * @fn uintptr_t kasan_get_poisoned_shadow_address(uintptr_t, size_t) + * @brief Wrapper to get poisoned shadow address + * @param addr + * @param size + * @return + */ +uintptr_t kasan_get_poisoned_shadow_address( + const uintptr_t addr, + const size_t size +) { + const uintptr_t addr_shadow_start = KASAN_MEM_TO_SHADOW( addr ); + const uintptr_t addr_shadow_end = KASAN_MEM_TO_SHADOW( addr + size - 1 ) + 1; + uintptr_t non_zero_shadow_addr = 0; + + for ( uintptr_t i = 0; i < addr_shadow_end - addr_shadow_start; i++ ) { + if ( *( uint8_t* )( addr_shadow_start + i ) ) { + non_zero_shadow_addr = addr_shadow_start + i; + break; + } + } + + if ( non_zero_shadow_addr ) { + const uintptr_t last_byte = addr + size - 1; + const int8_t *last_shadow_byte = ( int8_t* )KASAN_MEM_TO_SHADOW( last_byte ); + + // Non-zero bytes in shadow memory may indicate either: + // 1) invalid memory access (0xff, 0xfa, ...) + // 2) access to a 8-byte region which isn't entirely accessible, i.e. only + // n bytes can be read/written in the 8-byte region, where n < 8 + // (in this case shadow byte encodes how much bytes in an 8-byte region + // are accessible). + // Thus, if there is a non-zero shadow byte we need to check if it + // corresponds to the last byte in the checked region: + // not last - OOB memory access + // last - check if we don't access beyond what's encoded in the shadow + // byte. + if ( non_zero_shadow_addr != ( uintptr_t )last_shadow_byte + || ( int8_t )( last_byte & KASAN_SHADOW_MASK ) >= *last_shadow_byte + ) { + return non_zero_shadow_addr; + } + } + + return 0; +} + +/** + * @fn void kasan_poison_shadow(uintptr_t, size_t, uint8_t, bool) + * @brief Poison shadow with map if set + * @param addr + * @param size + * @param val + * @param map + */ +void kasan_poison_shadow( + const uintptr_t addr, + const size_t size, + const uint8_t val, + const bool map +) { + const uintptr_t shadow_start = KASAN_MEM_TO_SHADOW( addr ); + const uintptr_t shadow_end = KASAN_MEM_TO_SHADOW( addr + size - 1 ) + 1; + const size_t shadow_length = shadow_end - shadow_start; + // perform map if set + if ( map ) { + for ( + uintptr_t map_addr = ROUND_DOWN_TO_FULL_PAGE( shadow_start ); + map_addr < shadow_end; + map_addr += PAGE_SIZE + ) { + // handle already mapped + if ( virt_is_mapped( map_addr ) ) { + continue; + } + // map it + assert( virt_map_address_random( + virt_current_kernel_context, + map_addr, + VIRT_MEMORY_TYPE_NORMAL_NC, + VIRT_PAGE_TYPE_READ | VIRT_PAGE_TYPE_WRITE + ) ); + } + } + memset( ( void* )shadow_start, val, shadow_length ); +} + +/** + * @fn void kasan_unpoison_shadow(uintptr_t, size_t) + * @brief Wrapper to unpoison shadow address + * @param address + * @param size + */ +void kasan_unpoison_shadow( const uintptr_t address, const size_t size ) { + kasan_poison_shadow( + address, + size & ~KASAN_SHADOW_MASK, + ASAN_SHADOW_UNPOISONED_MAGIC, + false + ); + if (size & KASAN_SHADOW_MASK) { + auto uint8_t *shadow = ( uint8_t* )KASAN_MEM_TO_SHADOW( address + size ); + *shadow = size & KASAN_SHADOW_MASK; + } +} + +/** + * @fn int kasan_check_memory(uintptr_t, size_t, bool, uintptr_t) + * @brief Kasan check memory helper + * @param addr + * @param size + * @param write + * @param pc + * @return + */ +int kasan_check_memory( + const uintptr_t addr, + const size_t size, + const bool write, + const uintptr_t pc +) { + // handle no size + if ( ! size ) { + return 1; + } + // handle not in memory + if ( addr < HEAP_START || addr > HEAP_START + HEAP_MAX_SIZE ) { + return 1; + } + // get poisoned shadow address + const uintptr_t buggy_shadow_address = kasan_get_poisoned_shadow_address( + addr, size ); + if ( ! buggy_shadow_address ) { + return 1; + } + // report bug + kasan_bug_report( addr, size, buggy_shadow_address, write, pc ); + return 0; +} + +/** + * @fn void kasan_init(void) + * @brief Kasan init method + */ +void kasan_init( void ) { + kasan_poison_shadow( + HEAP_START, + HEAP_MIN_SIZE, + ASAN_SHADOW_RESERVED_MAGIC, + true + ); +} + +void __asan_handle_no_return( void ) {} + +void __asan_store1_noabort( uintptr_t address ) { + kasan_check_memory( address, 1, true, KASAN_CALLER_PC ); +} + +void __asan_store2_noabort( uintptr_t address ) { + kasan_check_memory( address, 2, true, KASAN_CALLER_PC ); +} + +void __asan_store4_noabort( uintptr_t address ) { + kasan_check_memory( address, 4, true, KASAN_CALLER_PC ); } -void __asan_store1_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_store8_noabort( uintptr_t address ) { + kasan_check_memory( address, 8, true, KASAN_CALLER_PC ); } -void __asan_store4_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_store16_noabort( uintptr_t address ) { + kasan_check_memory( address, 16, true, KASAN_CALLER_PC ); } -void __asan_store8_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_storeN_noabort( uintptr_t address, size_t size ) { + kasan_check_memory( address, size, true, KASAN_CALLER_PC ); } -void __asan_storeN_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_load1_noabort( uintptr_t address ) { + kasan_check_memory( address, 1, false, KASAN_CALLER_PC ); } -void __asan_load1_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_load2_noabort( uintptr_t address ) { + kasan_check_memory( address, 2, false, KASAN_CALLER_PC ); } -void __asan_load2_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_load4_noabort( uintptr_t address ) { + kasan_check_memory( address, 4, false, KASAN_CALLER_PC ); } -void __asan_load4_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_load8_noabort( uintptr_t address ) { + kasan_check_memory( address, 8, false, KASAN_CALLER_PC ); } -void __asan_load8_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_load16_noabort( uintptr_t address ) { + kasan_check_memory( address, 16, false, KASAN_CALLER_PC ); } -void __asan_loadN_noabort( [[maybe_unused]] uintptr_t address ) { +void __asan_loadN_noabort( uintptr_t address, size_t size ) { + kasan_check_memory( address, size, false, KASAN_CALLER_PC ); } diff --git a/bolthur/kernel/lib/kasan/kasan.h b/bolthur/kernel/lib/kasan/kasan.h index de0b8552..a31f94dd 100644 --- a/bolthur/kernel/lib/kasan/kasan.h +++ b/bolthur/kernel/lib/kasan/kasan.h @@ -21,17 +21,66 @@ #define _LIB_KASAN_KASAN_H #include +#include +#include "../../mm/heap.h" +#define KASAN_CALLER_PC ( ( uintptr_t )__builtin_return_address( 0 ) ) + +#define KASAN_SHADOW_SHIFT 3 +#define KASAN_SHADOW_GRANULE_SIZE ( 1UL << KASAN_SHADOW_SHIFT ) +#define KASAN_SHADOW_MASK ( KASAN_SHADOW_GRANULE_SIZE - 1 ) + +#define ASAN_SHADOW_UNPOISONED_MAGIC 0x00 +#define ASAN_SHADOW_RESERVED_MAGIC 0xff +#define ASAN_SHADOW_GLOBAL_REDZONE_MAGIC 0xf9 +#define ASAN_SHADOW_HEAP_HEAD_REDZONE_MAGIC 0xfa +#define ASAN_SHADOW_HEAP_TAIL_REDZONE_MAGIC 0xfb +#define ASAN_SHADOW_HEAP_FREE_MAGIC 0xfd + +typedef struct { + size_t aligned_size; + size_t dummy; +} kasan_heap_header_t; + +#define KASAN_HEAP_HEAD_REDZONE_SIZE sizeof( kasan_heap_header_t ) +#define KASAN_HEAP_TAIL_REDZONE_SIZE sizeof( kasan_heap_header_t ) + +#define KASAN_MEM_TO_SHADOW( addr ) ( ( ( addr ) >> KASAN_SHADOW_SHIFT ) + KASAN_SHADOW_MEMORY_OFFSET ) +#define KASAN_SHADOW_TO_MEM( shadow ) ( ( ( shadow ) - KASAN_SHADOW_MEMORY_OFFSET ) << KASAN_SHADOW_SHIFT ) + +// printing related functions +void kasan_print_16_bytes_no_bug(const char*, uintptr_t ); +void kasan_print_16_bytes_with_bug(const char*, uintptr_t, uintptr_t ); +void kasan_print_shadow_memory( uintptr_t, uintptr_t, uintptr_t ); +void kasan_bug_report( uintptr_t, size_t, uintptr_t, bool, uintptr_t ); + +// poison and check memory +uintptr_t kasan_get_poisoned_shadow_address( uintptr_t, size_t ); +void kasan_poison_shadow( uintptr_t, size_t, uint8_t, bool ); +void kasan_unpoison_shadow( uintptr_t, size_t ); +int kasan_check_memory( uintptr_t, size_t, bool, uintptr_t ); + +// hook functions +void* kasan_aligned_alloc_hook( size_t, size_t ); +void kasan_free_hook( void* ); + +// init +void kasan_init( void ); + +// asan functions void __asan_store1_noabort( uintptr_t ); +void __asan_store2_noabort( uintptr_t ); void __asan_store4_noabort( uintptr_t ); void __asan_store8_noabort( uintptr_t ); -void __asan_storeN_noabort( uintptr_t ); +void __asan_store16_noabort( uintptr_t ); +void __asan_storeN_noabort( uintptr_t, size_t ); void __asan_load1_noabort( uintptr_t ); void __asan_load2_noabort( uintptr_t ); void __asan_load4_noabort( uintptr_t ); void __asan_load8_noabort( uintptr_t ); -void __asan_loadN_noabort( uintptr_t ); +void __asan_load16_noabort( uintptr_t ); +void __asan_loadN_noabort( uintptr_t, size_t ); void __asan_handle_no_return( void ); diff --git a/bolthur/kernel/lib/kasan/print.c b/bolthur/kernel/lib/kasan/print.c new file mode 100644 index 00000000..bcd07c68 --- /dev/null +++ b/bolthur/kernel/lib/kasan/print.c @@ -0,0 +1,82 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../stdio.h" +#include "kasan.h" + +void kasan_print_16_bytes_no_bug(const char *prefix, const uintptr_t address) { + printf("%s%#"PRIxPTR":", prefix, address); + for (uintptr_t i = 0; i < 16; i++) printf(" %02X", *(uint8_t *)(address + i)); + printf("\r\n"); +} + +void kasan_print_16_bytes_with_bug(const char* prefix, const uintptr_t address, const uintptr_t buggy_offset) { + printf("%s0x%X:", prefix, address); + for (uintptr_t i = 0; i < buggy_offset; i++) + printf(" %02"PRIx8"", *(uint8_t *)(address + i)); + printf("[%02"PRIx8"]", *(uint8_t *)(address + buggy_offset)); + if (buggy_offset < 15) + printf("%02"PRIx8, *(uint8_t *)(address + buggy_offset + 1)); + for (uintptr_t i = buggy_offset + 2; i < 16; i++) + printf(" %02"PRIx8"", *(uint8_t *)(address + i)); + printf("\r\n"); +} + +void kasan_print_shadow_memory( const uintptr_t addr, const uintptr_t before, const uintptr_t after ) { + uintptr_t shadow_address = KASAN_MEM_TO_SHADOW( addr ); + uintptr_t aligned_shadow = shadow_address & 0xfffffff0; + uintptr_t buggy_offset = shadow_address - aligned_shadow; + + printf( "[KASan] Shadow bytes around the buggy address %#"PRIxPTR" (shadow %#"PRIxPTR"):\r\n", + addr, shadow_address ); + + for (uintptr_t i = before; i > 0; i--) { + kasan_print_16_bytes_no_bug("[KASan] ", aligned_shadow - i * 16); + } + + kasan_print_16_bytes_with_bug("[KASan] =>", aligned_shadow, buggy_offset); + + for (uintptr_t i = 1; i <= after; i++) { + kasan_print_16_bytes_no_bug("[KASan] ", aligned_shadow + i * 16); + } +} + +/** + * @fn void kasan_bug_report(uintptr_t, size_t, uintptr_t, bool, uintptr_t) + * @brief Wrapper to print found bug + * @param addr + * @param size + * @param buggy_shadow_address + * @param write + * @param pc + */ +void kasan_bug_report( + const uintptr_t addr, + const size_t size, + const uintptr_t buggy_shadow_address, + const bool write, + const uintptr_t pc +) { + [[maybe_unused]] uintptr_t buggy_address = KASAN_SHADOW_TO_MEM( buggy_shadow_address ); + printf( "[KASan] ===================================================\r\n" ); + printf( "[KASan] ERROR: Invalid memory access: address %#"PRIxPTR", size %zu, write %d, ip %#"PRIxPTR"\r\n", + addr, size, write ? 1 : 0, pc ); + //kasan_print_shadow_memory( buggy_address, 3, 3 ); +} diff --git a/bolthur/kernel/lib/libc/stdlib/aligned_alloc.c b/bolthur/kernel/lib/libc/stdlib/aligned_alloc.c index b59f07d1..13dd8f13 100644 --- a/bolthur/kernel/lib/libc/stdlib/aligned_alloc.c +++ b/bolthur/kernel/lib/libc/stdlib/aligned_alloc.c @@ -20,6 +20,9 @@ #include #include "../../stdlib.h" #include "../../../mm/heap.h" +#if defined( HAS_SANITIZER ) + #include "../../kasan/kasan.h" +#endif /** * @fn void aligned_alloc*(size_t, size_t) @@ -34,6 +37,12 @@ __allocator void* aligned_alloc( size_t alignment, size_t size ) { if ( 0 == size ) { return NULL; } - // use heap allocation - return heap_allocate( alignment, size ); + // sanitizer stuff + #if defined( HAS_SANITIZER ) + return kasan_aligned_alloc_hook( alignment, size ); + // no sanitizer stuff + #else + // use heap allocation + return heap_allocate( alignment, size ); + #endif } diff --git a/bolthur/kernel/lib/libc/stdlib/free.c b/bolthur/kernel/lib/libc/stdlib/free.c index 0345e49e..44efc950 100644 --- a/bolthur/kernel/lib/libc/stdlib/free.c +++ b/bolthur/kernel/lib/libc/stdlib/free.c @@ -19,6 +19,9 @@ #include "../../stdlib.h" #include "../../../mm/heap.h" +#if defined( HAS_SANITIZER ) + #include "../../kasan/kasan.h" +#endif /** * @fn void free(void*) @@ -27,5 +30,11 @@ * @param ptr ptr to address to free */ void free( void* ptr ) { - heap_free( ptr ); + // sanitizer stuff + #if defined( HAS_SANITIZER ) + kasan_free_hook( ptr ); + // non sanitizer stuff + #else + heap_free( ptr ); + #endif } diff --git a/bolthur/kernel/lib/libc/string/memcpy.c b/bolthur/kernel/lib/libc/string/memcpy.c index 6a9ee4f5..980761dd 100644 --- a/bolthur/kernel/lib/libc/string/memcpy.c +++ b/bolthur/kernel/lib/libc/string/memcpy.c @@ -21,6 +21,9 @@ #include #include "../../string.h" #include "../../../mm/virt.h" +#if defined( HAS_SANITIZER ) + #include "../../kasan/kasan.h" +#endif #define U64_BLOCK_SIZE sizeof( uint64_t ) #define UNALIGNED(a, b) ((( uintptr_t )a & ( U64_BLOCK_SIZE - 1 )) | (( uintptr_t )b & ( U64_BLOCK_SIZE - 1 ))) @@ -35,6 +38,11 @@ * @param size */ void* memcpy( void* restrict dst, const void* restrict src, size_t size ) { + #if defined( HAS_SANITIZER ) + kasan_check_memory( ( uintptr_t )dst, size, 1, KASAN_CALLER_PC ); + kasan_check_memory( ( uintptr_t )src, size, 1, KASAN_CALLER_PC ); + #endif + uint8_t* u8_dst = ( uint8_t * )dst; const uint8_t* u8_src = ( const uint8_t * )src; // copy in 4 byte chunks diff --git a/bolthur/kernel/lib/libc/string/memset.c b/bolthur/kernel/lib/libc/string/memset.c index c7bc4e63..0e2d5967 100644 --- a/bolthur/kernel/lib/libc/string/memset.c +++ b/bolthur/kernel/lib/libc/string/memset.c @@ -20,6 +20,9 @@ #include #include #include "../../string.h" +#if defined( HAS_SANITIZER ) + #include "../../kasan/kasan.h" +#endif #define U64_BLOCK_SIZE sizeof( uint64_t ) #define BUFFER_UNALIGNED(val) (( uintptr_t )val & ( U64_BLOCK_SIZE - 1 )) @@ -34,9 +37,13 @@ * @param size length * @return void* address to buffer */ -void* memset( void* buf, int value, size_t size ) { - uint8_t* u8_buf = ( uint8_t* )buf; - uint8_t u8_value = ( uint8_t )value; +void* memset( void* buf, const int value, size_t size ) { + #if defined( HAS_SANITIZER ) + kasan_check_memory( ( uintptr_t )buf, size, 1, KASAN_CALLER_PC ); + #endif + + auto uint8_t* u8_buf = ( uint8_t* )buf; + const uint8_t u8_value = ( uint8_t )value; // set until alignment fits while( BUFFER_UNALIGNED( u8_buf ) ) { @@ -51,7 +58,7 @@ void* memset( void* buf, int value, size_t size ) { // set in 8 byte steps as it's now aligned if ( ! SIZE_TOO_SMALL( size ) ) { // prepare value for set - uint64_t u64_value = ( uint64_t )u8_value << 56 + const uint64_t u64_value = ( uint64_t )u8_value << 56 | ( uint64_t )u8_value << 48 | ( uint64_t )u8_value << 40 | ( uint64_t )u8_value << 32 @@ -60,7 +67,7 @@ void* memset( void* buf, int value, size_t size ) { | ( uint64_t )u8_value << 8 | ( uint64_t )u8_value; // set pointer - uint64_t* u64_buf = ( uint64_t* )u8_buf; + auto uint64_t* u64_buf = ( uint64_t* )u8_buf; // set as much as possible at once while ( size >= U64_BLOCK_SIZE * 4 ) { *u64_buf++ = u64_value; @@ -74,6 +81,7 @@ void* memset( void* buf, int value, size_t size ) { *u64_buf++ = u64_value; size -= U64_BLOCK_SIZE; } + u8_buf = ( uint8_t* )u64_buf; } // set rest while( size-- ) { diff --git a/bolthur/kernel/lib/libc/string/strlen.c b/bolthur/kernel/lib/libc/string/strlen.c index c3848bab..588528ca 100644 --- a/bolthur/kernel/lib/libc/string/strlen.c +++ b/bolthur/kernel/lib/libc/string/strlen.c @@ -23,10 +23,6 @@ #include "../../../mm/virt.h" #include "../../../debug/debug.h" -#define U64_BLOCK_SIZE sizeof( uint64_t ) -#define BUFFER_UNALIGNED(val) ( ( uintptr_t )val & ( U64_BLOCK_SIZE - 1 ) ) -#define DETECT_NULL_ENDING(x) ( ( x - 0x0101010101010101) & ~x & 0x8080808080808080 ) - /** * @fn size_t strlen(const char*) * @brief Get string length @@ -40,22 +36,7 @@ size_t strlen( const char* str ) { if ( ! str ) { return 0; } - // loop until alignment - while( BUFFER_UNALIGNED( str ) ) { - // handle end reached - if ( !*str ) { - return ( size_t )( str - start ); - } - // increment - str++; - } - // use 64bit for checks - uint64_t* aligned = ( uint64_t* )str; - while ( ! DETECT_NULL_ENDING( *aligned ) ) { - aligned++; - } - // update str - str = ( const char* )aligned; + // loop until null termination while ( *str ) { str++; } @@ -77,7 +58,7 @@ size_t strlen_unsafe( const char* str ) { } // variables uintptr_t last_check = ROUND_DOWN_TO_FULL_PAGE( str ); - const char* next_check = ( const char* )( last_check + PAGE_SIZE ); + auto const char* next_check = ( const char* )( last_check + PAGE_SIZE ); const char* start = str; // loop until end is reached or some memory is not mapped do { @@ -85,13 +66,8 @@ size_t strlen_unsafe( const char* str ) { if ( ! virt_is_mapped_range( last_check, PAGE_SIZE ) ) { return 0; } - // loop until alignment - while( BUFFER_UNALIGNED( str ) && str < next_check ) { - // handle end reached - if ( !*str ) { - return ( size_t )( str - start ); - } - // increment + // continue unaligned check + while ( *str && str < next_check ) { str++; } // handle page boundary reached @@ -100,24 +76,6 @@ size_t strlen_unsafe( const char* str ) { next_check = ( const char* )( last_check + PAGE_SIZE ); continue; } - // use 64bit for checks - uint64_t* aligned = ( uint64_t* )str; - uint64_t* aligned_end = ( uint64_t* )next_check; - while ( ! DETECT_NULL_ENDING( *aligned ) && aligned < aligned_end ) { - aligned++; - } - // update str - str = ( const char* )aligned; - // handle page boundary reached - if ( str == next_check ) { - last_check = ( uintptr_t )next_check; - next_check = ( const char* )( last_check + PAGE_SIZE ); - continue; - } - // continue unaligned check - while ( *str && str < next_check ) { - str++; - } // handle page boundary reached if ( str == next_check ) { last_check = ( uintptr_t )next_check; diff --git a/bolthur/kernel/main.c b/bolthur/kernel/main.c index f1ddbe58..f3a2673a 100644 --- a/bolthur/kernel/main.c +++ b/bolthur/kernel/main.c @@ -128,14 +128,14 @@ void kernel_main( void ) { tar_header_t* boot = tar_lookup_file( initrd_get_start_address(), "boot" ); assert( boot ) // Get file address and size - uintptr_t elf_file = ( uintptr_t )tar_file( boot ); + const uintptr_t elf_file = ( uintptr_t )tar_file( boot ); // Create process DEBUG_OUTPUT( "[bolthur/kernel -> process -> init] create ...\r\n" ) task_process_t* proc = task_process_create( 0, 0 ); assert( proc ) // load flat image - uintptr_t init_entry = elf_load( elf_file, proc ); + const uintptr_t init_entry = elf_load( elf_file, proc ); assert( init_entry ) // add thread assert( task_thread_create( init_entry, proc, 0 ) ) @@ -143,6 +143,10 @@ void kernel_main( void ) { DEBUG_OUTPUT( "[bolthur/kernel -> process -> init] prepare ...\r\n" ) assert( task_process_prepare_init( proc ) ) + // unmap initrd in kernel + DEBUG_OUTPUT( "[bolthur/kernel -> initrd] unmap in kernel ...\r\n" ) + initrd_unmap(); + // Setup timer DEBUG_OUTPUT( "[bolthur/kernel -> timer] initialize ...\r\n" ) timer_init(); diff --git a/bolthur/kernel/mm/heap.c b/bolthur/kernel/mm/heap.c index 3e630079..0b09b0d6 100644 --- a/bolthur/kernel/mm/heap.c +++ b/bolthur/kernel/mm/heap.c @@ -29,6 +29,9 @@ #include "../mm/heap.h" #include "../panic.h" #include "../debug/debug.h" +#if defined( HAS_SANITIZER ) + #include "../lib/kasan/kasan.h" +#endif void* dlmemalign( size_t, size_t ); void dlfree( void* ); @@ -48,6 +51,15 @@ bool heap_init_get( void ) { return ( bool )kernel_heap; } +/** + * @fn heap_init_state_t heap_get_state(void) + * @brief Wrapper to get init state + * @return + */ +heap_init_state_t heap_get_state( void ) { + return kernel_heap->state; +} + /** * @fn void heap_init(heap_init_state_t) * @brief new heap init implementation @@ -91,6 +103,13 @@ void heap_init( heap_init_state_t state ) { VIRT_PAGE_TYPE_READ | VIRT_PAGE_TYPE_WRITE ) ) } + // init kasan + #if defined( HAS_SANITIZER ) + #if defined( PRINT_MM_HEAP ) + DEBUG_OUTPUT( "Initializing kasan\r\n" ) + #endif + kasan_init(); + #endif // set state kernel_heap->state = state; // skip rest @@ -469,8 +488,11 @@ void* heap_sbrk( intptr_t increment ) { #endif return ( void* )-1; } - // clear area - memset( ( void* )addr, 0, PAGE_SIZE ); + // sanitizer stuff + #if defined( HAS_SANITIZER ) + // poison area + kasan_poison_shadow( addr, PAGE_SIZE, ASAN_SHADOW_RESERVED_MAGIC, true ); + #endif // update max heap address min_heap += PAGE_SIZE; } diff --git a/bolthur/kernel/mm/heap.h b/bolthur/kernel/mm/heap.h index 66904eea..f3dc35ad 100644 --- a/bolthur/kernel/mm/heap.h +++ b/bolthur/kernel/mm/heap.h @@ -29,10 +29,20 @@ #define HEAP_MAX_SIZE 0xFFFFFFF #define HEAP_MIN_SIZE 0x10000 #define HEAP_EXTENSION 0x1000 + #if defined( HAS_SANITIZER ) + #define KASAN_SHADOW_MEMORY_OFFSET 0xC6000000 + #define KASAN_SHADOW_MEMORY_MAP_OFFSET 0x10000000 + #define KASAN_SHADOW_MEMORY_START 0xE0000000 + #define KASAN_SHADOW_MEMORY_MIN_SIZE 0x10000 + #define KASAN_SHADOW_MEMORY_MAX_SIZE 0xFFFFFFF + #endif #elif defined( ELF64 ) #error "Heap not ready for x64" #endif +extern uintptr_t __initial_heap_start; +extern uintptr_t __initial_heap_end; + typedef enum { HEAP_INIT_EARLY = 0, HEAP_INIT_NORMAL, @@ -58,10 +68,8 @@ typedef struct { heap_block_t* free; } heap_manager_t; -extern uintptr_t __initial_heap_start; -extern uintptr_t __initial_heap_end; - bool heap_init_get( void ); +heap_init_state_t heap_get_state( void ); void heap_init( heap_init_state_t ); void* heap_allocate( size_t, size_t ); void heap_free( void* ); diff --git a/bolthur/kernel/mm/virt.c b/bolthur/kernel/mm/virt.c index 1a0c6046..4b82c988 100644 --- a/bolthur/kernel/mm/virt.c +++ b/bolthur/kernel/mm/virt.c @@ -106,10 +106,10 @@ void virt_init( void ) { #endif // map initial heap similar to normal heap non cachable - uintptr_t phys_bss_start = VIRT_2_PHYS( &__bss_start ); - uintptr_t phys_bss_end = VIRT_2_PHYS( &__bss_end ); - uintptr_t phys_data_start = VIRT_2_PHYS( &__data_start ); - uintptr_t phys_data_end = VIRT_2_PHYS( &__data_end ); + const uintptr_t phys_bss_start = VIRT_2_PHYS( &__bss_start ); + const uintptr_t phys_bss_end = VIRT_2_PHYS( &__bss_end ); + const uintptr_t phys_data_start = VIRT_2_PHYS( &__data_start ); + const uintptr_t phys_data_end = VIRT_2_PHYS( &__data_end ); // map from start to end addresses as used while ( start < end ) { diff --git a/bolthur/kernel/platform/raspi/mailbox/property.c b/bolthur/kernel/platform/raspi/mailbox/property.c index bc47a686..6b3dfa98 100644 --- a/bolthur/kernel/platform/raspi/mailbox/property.c +++ b/bolthur/kernel/platform/raspi/mailbox/property.c @@ -54,6 +54,7 @@ void mailbox_property_init( void ) { if ( ! ptb_buffer ) { ptb_buffer = aligned_alloc( PAGE_SIZE, PAGE_SIZE ); assert( ptb_buffer ) + memset( ptb_buffer, 0, PAGE_SIZE ); ptb_buffer_phys = ( int32_t* )VIRT_2_PHYS( ptb_buffer ); } // clear out buffer diff --git a/bolthur/kernel/platform/raspi/mm/phys.c b/bolthur/kernel/platform/raspi/mm/phys.c index 7b26051e..32741e67 100644 --- a/bolthur/kernel/platform/raspi/mm/phys.c +++ b/bolthur/kernel/platform/raspi/mm/phys.c @@ -106,12 +106,14 @@ bool phys_platform_init( void ) { if ( ! phys_bitmap ) { return false; } + memset( phys_bitmap, 0, phys_bitmap_length * sizeof( uint32_t ) ); phys_bitmap_check = aligned_alloc( sizeof( *phys_bitmap ), phys_bitmap_length * sizeof( uint32_t ) ); if ( ! phys_bitmap_check ) { return false; } + memset( phys_bitmap_check, 0, phys_bitmap_length * sizeof( uint32_t ) ); // debug output #if defined( PRINT_MM_PHYS ) DEBUG_OUTPUT( "total memory amount: %#"PRIx32"\r\n", memory_amount ) diff --git a/bolthur/kernel/syscall/print.c b/bolthur/kernel/syscall/print.c index 29b67f03..604a1fab 100644 --- a/bolthur/kernel/syscall/print.c +++ b/bolthur/kernel/syscall/print.c @@ -46,7 +46,7 @@ void syscall_kernel_putc( void* context ) { */ void syscall_kernel_puts( void* context ) { // get parameter - char* str = ( char* )syscall_get_parameter( context, 0 ); + auto char* str = ( char* )syscall_get_parameter( context, 0 ); size_t len = ( size_t )syscall_get_parameter( context, 1 ); // debug output #if defined( PRINT_SYSCALL ) @@ -66,7 +66,7 @@ void syscall_kernel_puts( void* context ) { DEBUG_OUTPUT( "Allocate memory for unsafe copy!\r\n" ) #endif // allocate space for duplicate and check for error - char* data_dup = ( char* )malloc( sizeof( char ) * ( len + 1 ) ); + auto char* data_dup = ( char* )malloc( sizeof( char ) * ( len + 1 ) ); if ( ! data_dup ) { // debug output #if defined( PRINT_SYSCALL ) @@ -95,7 +95,7 @@ void syscall_kernel_puts( void* context ) { return; } // print somewhere - int written = printf( "%.*s", len, data_dup ); + const int written = printf( "%.*s", len, data_dup ); // free data_dup and return written amount free( data_dup ); // print until end of string or len diff --git a/bolthur/kernel/syscall/rpc.c b/bolthur/kernel/syscall/rpc.c index 206bd542..abe06579 100644 --- a/bolthur/kernel/syscall/rpc.c +++ b/bolthur/kernel/syscall/rpc.c @@ -271,7 +271,7 @@ void syscall_rpc_raise( void* context ) { */ void syscall_rpc_ret( void* context ) { size_t type = syscall_get_parameter( context, 0 ); - void* data = ( void* )syscall_get_parameter( context, 1 ); + auto void* data = ( void* )syscall_get_parameter( context, 1 ); size_t length = syscall_get_parameter( context, 2 ); size_t original_rpc_id = syscall_get_parameter( context, 3 ); #if defined( PRINT_SYSCALL ) @@ -399,7 +399,7 @@ void syscall_rpc_ret( void* context ) { // loop until usable thread has been found while ( current && ! target ) { // get thread - task_thread_t* tmp = TASK_THREAD_GET_BLOCK( current ); + auto task_thread_t* tmp = TASK_THREAD_GET_BLOCK( current ); // FIXME: CHECK IF ACTIVE target = tmp; // get next thread diff --git a/bolthur/server/libhelper.h b/bolthur/server/libhelper.h index 6b4ccf55..911fd8b9 100644 --- a/bolthur/server/libhelper.h +++ b/bolthur/server/libhelper.h @@ -29,6 +29,71 @@ #include #include +/** + * @fn int get_file_handler(const char*) + * @brief Wrapper to get file handler + * @param path + * @return + */ +[[maybe_unused]] static int get_file_handler( const char* path ) { + // variables + vfs_stat_request_t* request = malloc( sizeof( vfs_stat_request_t ) ); + if ( ! request ) { + errno = ENOMEM; + return -1; + } + // clear message structures + memset( request, 0, sizeof( vfs_stat_request_t ) ); + // copy stuff to message + strncpy( request->file_path, path, PATH_MAX - 1 ); + // raise rpc and wait for return + const size_t response_id = bolthur_rpc_raise( + RPC_VFS_STAT, + VFS_DAEMON_ID, + request, + sizeof( vfs_stat_request_t ), + NULL, + RPC_VFS_STAT, + request, + sizeof( vfs_stat_request_t ), + 0, + 0, + NULL, + false + ); + // handle error + if ( 0 == response_id ) { + free( request ); + return -1; + } + size_t data_size; + vfs_stat_response_t* response = bolthur_rpc_fetch_from_mailbox( + response_id, + &data_size, + true, + NULL + ); + // handle error + if ( ! response ) { + free( request ); + return -1; + } + // handle failure + if ( ! response->success ) { + free( request ); + free( response ); + errno = EIO; + return -1; + } + // cache handler + const int handler = response->handler; + // free request and response + free( request ); + free( response ); + // return handler + return handler; +} + /** * @fn void send_vfs_add_request(vfs_add_request_t*, size_t, unsigned int) * @brief Helper to send add request with wait for response diff --git a/bolthur/server/usb/device/hub/global.h b/bolthur/server/usb/device/hub/global.h new file mode 100644 index 00000000..f13b5a5c --- /dev/null +++ b/bolthur/server/usb/device/hub/global.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include + +extern pid_t allowed_rpc_origin; + +#endif diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index fef82295..496c2bc9 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -30,6 +30,11 @@ #include "../../../libusbd.h" #include "../../../../library/usb/usb.h" +/** + * @brief Allowed rpc origin + */ +pid_t allowed_rpc_origin; + /** * @fn int main(int, char*[]) * @brief main entry point @@ -54,6 +59,13 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } + // query allowed rpc origin + allowed_rpc_origin = get_file_handler( USBD_DEVICE_PATH ); + if ( -1 == allowed_rpc_origin ) { + STARTUP_PRINT( "Unable to get handler id of %s\r\n", USBD_DEVICE_PATH ) + return -1; + } + // registering handler STARTUP_PRINT( "Registering handler at usbd\r\n" ) result = usb_register_handler( LIBUSB_INTERFACE_CLASS_HUB ); diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index 69c4695a..ad7c73f8 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -24,6 +24,7 @@ // local includes #include "../../hub.h" #include "../../rpc.h" +#include "../../global.h" #include "../../../../../libusbd.h" #include "../../../../../../library/usb/usb.h" @@ -597,6 +598,17 @@ void rpc_hub_attach( _syscall_rpc_cleanup(); return; } + + // validate origin + if ( + origin != allowed_rpc_origin + && ! bolthur_rpc_validate_origin( origin, data_info ) + ) { + STARTUP_PRINT( "INVALID ORIGIN!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // get data from mailbox size_t data_size; vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( @@ -606,6 +618,7 @@ void rpc_hub_attach( _syscall_rpc_cleanup(); return; } + // allocate space for pull_request const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; diff --git a/build-aux/platform/raspi/memory_map.md b/build-aux/platform/raspi/memory_map.md index 0f90e325..9e827a1e 100644 --- a/build-aux/platform/raspi/memory_map.md +++ b/build-aux/platform/raspi/memory_map.md @@ -10,7 +10,8 @@ kernel area: 0x80000000 - 0xBFFFFFFF => unused area 0xC0000000 - 0xCFFFFFFF => kernel space 0xD0000000 - 0xDFFFFFFF => kernel heap - 0xE0000000 - 0xF0FFFFFF => unused area + 0xE0000000 - 0xEFFFFFFF => kasan space if enabled + 0xF0000000 - 0xF0FFFFFF => unused area 0xF1000000 - 0xF1FFFFFF => temporary area 0xF2000000 - 0xF2FFFFFF => gpio peripheral 0xF3000000 - 0xF303FFFF => local peripheral ( raspi 2 / 3 only ) diff --git a/thirdparty/dlmalloc/dlmalloc.c b/thirdparty/dlmalloc/dlmalloc.c index aaa64632..9382888c 100644 --- a/thirdparty/dlmalloc/dlmalloc.c +++ b/thirdparty/dlmalloc/dlmalloc.c @@ -2731,7 +2731,7 @@ static struct malloc_state _gm_; ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) /* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char* addr) { +__attribute__((no_sanitize("kernel-address"))) static msegmentptr segment_holding(mstate m, char* addr) { msegmentptr sp = &m->seg; for (;;) { if (addr >= sp->base && addr < sp->base + sp->size) @@ -2742,7 +2742,7 @@ static msegmentptr segment_holding(mstate m, char* addr) { } /* Return true if segment contains a segment link */ -static int has_segment_link(mstate m, msegmentptr ss) { +__attribute__((no_sanitize("kernel-address"))) static int has_segment_link(mstate m, msegmentptr ss) { msegmentptr sp = &m->seg; for (;;) { if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) @@ -3132,7 +3132,7 @@ static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } #endif /* LOCK_AT_FORK */ /* Initialize mparams */ -static int init_mparams(void) { +__attribute__((no_sanitize("kernel-address"))) static int init_mparams(void) { #ifdef NEED_GLOBAL_LOCK_INIT if (malloc_global_mutex_status <= 0) init_malloc_global_mutex(); @@ -3222,7 +3222,7 @@ static int init_mparams(void) { } /* support for mallopt */ -static int change_mparam(int param_number, int value) { +__attribute__((no_sanitize("kernel-address"))) static int change_mparam(int param_number, int value) { size_t val; ensure_initialization(); val = (value == -1)? MAX_SIZE_T : (size_t)value; @@ -3517,7 +3517,7 @@ static void do_check_malloc_state(mstate m) { /* ----------------------------- statistics ------------------------------ */ #if !NO_MALLINFO -static struct mallinfo internal_mallinfo(mstate m) { +__attribute__((no_sanitize("kernel-address"))) static struct mallinfo internal_mallinfo(mstate m) { struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ensure_initialization(); if (!PREACTION(m)) { @@ -3856,7 +3856,7 @@ static void internal_malloc_stats(mstate m) { */ /* Malloc using mmap */ -static void* mmap_alloc(mstate m, size_t nb) { +__attribute__((no_sanitize("kernel-address"))) static void* mmap_alloc(mstate m, size_t nb) { size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); if (m->footprint_limit != 0) { size_t fp = m->footprint + mmsize; @@ -3888,7 +3888,7 @@ static void* mmap_alloc(mstate m, size_t nb) { } /* Realloc using mmap */ -static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { +__attribute__((no_sanitize("kernel-address"))) static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { size_t oldsize = chunksize(oldp); (void)flags; /* placate people compiling -Wunused */ if (is_small(nb)) /* Can't shrink mmap regions below small size */ @@ -3926,7 +3926,7 @@ static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { /* -------------------------- mspace management -------------------------- */ /* Initialize top chunk and its size */ -static void init_top(mstate m, mchunkptr p, size_t psize) { +__attribute__((no_sanitize("kernel-address"))) static void init_top(mstate m, mchunkptr p, size_t psize) { /* Ensure alignment */ size_t offset = align_offset(chunk2mem(p)); p = (mchunkptr)((char*)p + offset); @@ -3941,7 +3941,7 @@ static void init_top(mstate m, mchunkptr p, size_t psize) { } /* Initialize bins for a new mstate that is otherwise zeroed out */ -static void init_bins(mstate m) { +__attribute__((no_sanitize("kernel-address"))) static void init_bins(mstate m) { /* Establish circular links for smallbins */ bindex_t i; for (i = 0; i < NSMALLBINS; ++i) { @@ -3970,7 +3970,7 @@ static void reset_on_error(mstate m) { #endif /* PROCEED_ON_ERROR */ /* Allocate chunk and prepend remainder with chunk in successor base. */ -static void* prepend_alloc(mstate m, char* newbase, char* oldbase, +__attribute__((no_sanitize("kernel-address"))) static void* prepend_alloc(mstate m, char* newbase, char* oldbase, size_t nb) { mchunkptr p = align_as_chunk(newbase); mchunkptr oldfirst = align_as_chunk(oldbase); @@ -4012,7 +4012,7 @@ static void* prepend_alloc(mstate m, char* newbase, char* oldbase, } /* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { +__attribute__((no_sanitize("kernel-address"))) static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { /* Determine locations and sizes of segment, fenceposts, old top */ char* old_top = (char*)m->top; msegmentptr oldsp = segment_holding(m, old_top); @@ -4067,7 +4067,7 @@ static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { /* -------------------------- System allocation -------------------------- */ /* Get memory from system using MORECORE or MMAP */ -static void* sys_alloc(mstate m, size_t nb) { +__attribute__((no_sanitize("kernel-address"))) static void* sys_alloc(mstate m, size_t nb) { char* tbase = CMFAIL; size_t tsize = 0; flag_t mmap_flag = 0; @@ -4278,7 +4278,7 @@ static void* sys_alloc(mstate m, size_t nb) { /* ----------------------- system deallocation -------------------------- */ /* Unmap and unlink any mmapped segments that don't contain used chunks */ -static size_t release_unused_segments(mstate m) { +__attribute__((no_sanitize("kernel-address"))) static size_t release_unused_segments(mstate m) { size_t released = 0; int nsegs = 0; msegmentptr pred = &m->seg; @@ -4325,7 +4325,7 @@ static size_t release_unused_segments(mstate m) { return released; } -static int sys_trim(mstate m, size_t pad) { +__attribute__((no_sanitize("kernel-address"))) static int sys_trim(mstate m, size_t pad) { size_t released = 0; ensure_initialization(); if (pad < MAX_REQUEST && is_initialized(m)) { @@ -4393,7 +4393,7 @@ static int sys_trim(mstate m, size_t pad) { /* Consolidate and bin a chunk. Differs from exported versions of free mainly in that the chunk need not be marked as inuse. */ -static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { +__attribute__((no_sanitize("kernel-address"))) static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { mchunkptr next = chunk_plus_offset(p, psize); if (!pinuse(p)) { mchunkptr prev; @@ -4464,7 +4464,7 @@ static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { /* ---------------------------- malloc --------------------------- */ /* allocate a large request from the best fitting chunk in a treebin */ -static void* tmalloc_large(mstate m, size_t nb) { +__attribute__((no_sanitize("kernel-address"))) static void* tmalloc_large(mstate m, size_t nb) { tchunkptr v = 0; size_t rsize = -nb; /* Unsigned negation */ tchunkptr t; @@ -4535,7 +4535,7 @@ static void* tmalloc_large(mstate m, size_t nb) { } /* allocate a small request from the best fitting chunk in a treebin */ -static void* tmalloc_small(mstate m, size_t nb) { +__attribute__((no_sanitize("kernel-address"))) static void* tmalloc_small(mstate m, size_t nb) { tchunkptr t, v; size_t rsize; bindex_t i; @@ -4574,7 +4574,7 @@ static void* tmalloc_small(mstate m, size_t nb) { #if !ONLY_MSPACES -void* dlmalloc(size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlmalloc(size_t bytes) { /* Basic algorithm: If a small request (< 256 bytes minus per-chunk overhead): @@ -4712,7 +4712,7 @@ void* dlmalloc(size_t bytes) { /* ---------------------------- free --------------------------- */ -void dlfree(void* mem) { +__attribute__((no_sanitize("kernel-address"))) void dlfree(void* mem) { /* Consolidate freed chunks with preceeding or succeeding bordering free chunks, if they exist, and then place in a bin. Intermixed @@ -4821,7 +4821,7 @@ void dlfree(void* mem) { #endif /* FOOTERS */ } -void* dlcalloc(size_t n_elements, size_t elem_size) { +__attribute__((no_sanitize("kernel-address"))) void* dlcalloc(size_t n_elements, size_t elem_size) { void* mem; size_t req = 0; if (n_elements != 0) { @@ -4841,7 +4841,7 @@ void* dlcalloc(size_t n_elements, size_t elem_size) { /* ------------ Internal support for realloc, memalign, etc -------------- */ /* Try to realloc; only in-place unless can_move true */ -static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, +__attribute__((no_sanitize("kernel-address"))) static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, int can_move) { mchunkptr newp = 0; size_t oldsize = chunksize(p); @@ -4920,7 +4920,7 @@ static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, return newp; } -static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { void* mem = 0; if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ alignment = MIN_CHUNK_SIZE; @@ -5001,7 +5001,7 @@ static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { bit 0 set if all elements are same size (using sizes[0]) bit 1 set if elements should be zeroed */ -static void** ialloc(mstate m, +__attribute__((no_sanitize("kernel-address"))) static void** ialloc(mstate m, size_t n_elements, size_t* sizes, int opts, @@ -5127,7 +5127,7 @@ static void** ialloc(mstate m, chunks before freeing, which will occur often if allocated with ialloc or the array is sorted. */ -static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { +__attribute__((no_sanitize("kernel-address"))) static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { size_t unfreed = 0; if (!PREACTION(m)) { void** a; @@ -5215,7 +5215,7 @@ static void internal_inspect_all(mstate m, #if !ONLY_MSPACES -void* dlrealloc(void* oldmem, size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlrealloc(void* oldmem, size_t bytes) { void* mem = 0; if (oldmem == 0) { mem = dlmalloc(bytes); @@ -5260,7 +5260,7 @@ void* dlrealloc(void* oldmem, size_t bytes) { return mem; } -void* dlrealloc_in_place(void* oldmem, size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlrealloc_in_place(void* oldmem, size_t bytes) { void* mem = 0; if (oldmem != 0) { if (bytes >= MAX_REQUEST) { @@ -5291,14 +5291,14 @@ void* dlrealloc_in_place(void* oldmem, size_t bytes) { return mem; } -void* dlmemalign(size_t alignment, size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlmemalign(size_t alignment, size_t bytes) { if (alignment <= MALLOC_ALIGNMENT) { return dlmalloc(bytes); } return internal_memalign(gm, alignment, bytes); } -int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { void* mem = 0; if (alignment == MALLOC_ALIGNMENT) mem = dlmalloc(bytes); @@ -5321,32 +5321,32 @@ int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { } } -void* dlvalloc(size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); pagesz = mparams.page_size; return dlmemalign(pagesz, bytes); } -void* dlpvalloc(size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) void* dlpvalloc(size_t bytes) { size_t pagesz; ensure_initialization(); pagesz = mparams.page_size; return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); } -void** dlindependent_calloc(size_t n_elements, size_t elem_size, +__attribute__((no_sanitize("kernel-address"))) void** dlindependent_calloc(size_t n_elements, size_t elem_size, void* chunks[]) { size_t sz = elem_size; /* serves as 1-element array */ return ialloc(gm, n_elements, &sz, 3, chunks); } -void** dlindependent_comalloc(size_t n_elements, size_t sizes[], +__attribute__((no_sanitize("kernel-address"))) void** dlindependent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]) { return ialloc(gm, n_elements, sizes, 0, chunks); } -size_t dlbulk_free(void* array[], size_t nelem) { +__attribute__((no_sanitize("kernel-address"))) size_t dlbulk_free(void* array[], size_t nelem) { return internal_bulk_free(gm, array, nelem); } @@ -5364,7 +5364,7 @@ void dlmalloc_inspect_all(void(*handler)(void *start, } #endif /* MALLOC_INSPECT_ALL */ -int dlmalloc_trim(size_t pad) { +__attribute__((no_sanitize("kernel-address"))) int dlmalloc_trim(size_t pad) { int result = 0; ensure_initialization(); if (!PREACTION(gm)) { @@ -5374,20 +5374,20 @@ int dlmalloc_trim(size_t pad) { return result; } -size_t dlmalloc_footprint(void) { +__attribute__((no_sanitize("kernel-address"))) size_t dlmalloc_footprint(void) { return gm->footprint; } -size_t dlmalloc_max_footprint(void) { +__attribute__((no_sanitize("kernel-address"))) size_t dlmalloc_max_footprint(void) { return gm->max_footprint; } -size_t dlmalloc_footprint_limit(void) { +__attribute__((no_sanitize("kernel-address"))) size_t dlmalloc_footprint_limit(void) { size_t maf = gm->footprint_limit; return maf == 0 ? MAX_SIZE_T : maf; } -size_t dlmalloc_set_footprint_limit(size_t bytes) { +__attribute__((no_sanitize("kernel-address"))) size_t dlmalloc_set_footprint_limit(size_t bytes) { size_t result; /* invert sense of 0 */ if (bytes == 0) result = granularity_align(1); /* Use minimal size */ @@ -5410,11 +5410,11 @@ void dlmalloc_stats() { } #endif /* NO_MALLOC_STATS */ -int dlmallopt(int param_number, int value) { +__attribute__((no_sanitize("kernel-address"))) int dlmallopt(int param_number, int value) { return change_mparam(param_number, value); } -size_t dlmalloc_usable_size(void* mem) { +__attribute__((no_sanitize("kernel-address"))) size_t dlmalloc_usable_size(void* mem) { if (mem != 0) { mchunkptr p = mem2chunk(mem); if (is_inuse(p)) From 59637091b3f515ac0f8ae1649ed33565fabecec9 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 29 Jul 2025 17:53:08 +0200 Subject: [PATCH 024/144] - Added constant for hid device path - Added libusb dependency and ldadd to hid Makefile.am - Ported global header from hub - Finished main of hid server - Added printing of surrounding memory to kasan with respect of mapped areas - Removed sanitizer defines from heap header and move last remaining into kasan - Added plain rpc to keyboard and mouse - Added main logic to keyboard and mouse - Created new libhid abstracting away hid operations - Removed usb storage from stage3 until hid, mouse and keyboard are done and a basic stack is there --- bolthur/kernel/lib/kasan/kasan.c | 11 ++ bolthur/kernel/lib/kasan/kasan.h | 9 ++ bolthur/kernel/lib/kasan/print.c | 88 ++++++++++---- bolthur/kernel/mm/heap.h | 7 -- bolthur/kernel/mm/shared.c | 2 +- bolthur/library/Makefile.am | 2 +- bolthur/library/configure.ac | 1 + bolthur/library/hid/Makefile.am | 6 + bolthur/library/hid/hid.c | 108 ++++++++++++++++++ bolthur/library/hid/hid.h | 28 +++++ bolthur/server/libusb.h | 5 + bolthur/server/libusbd.h | 14 +++ bolthur/server/usb/device/hid/hid/Makefile.am | 4 + bolthur/server/usb/device/hid/hid/global.h | 27 +++++ bolthur/server/usb/device/hid/hid/main.c | 56 ++++++++- .../usb/device/hid/keyboard/Makefile.am | 10 ++ .../server/usb/device/hid/keyboard/global.h | 27 +++++ bolthur/server/usb/device/hid/keyboard/main.c | 71 +++++++++++- bolthur/server/usb/device/hid/keyboard/rpc.h | 31 +++++ .../server/usb/device/hid/keyboard/rpc/init.c | 50 ++++++++ .../device/hid/keyboard/rpc/keyboard/attach.c | 43 +++++++ .../hid/keyboard/rpc/keyboard/deallocate.c | 37 ++++++ .../device/hid/keyboard/rpc/keyboard/detach.c | 37 ++++++ .../server/usb/device/hid/mouse/Makefile.am | 10 ++ bolthur/server/usb/device/hid/mouse/global.h | 27 +++++ bolthur/server/usb/device/hid/mouse/main.c | 71 +++++++++++- bolthur/server/usb/device/hid/mouse/rpc.h | 31 +++++ .../server/usb/device/hid/mouse/rpc/init.c | 50 ++++++++ .../usb/device/hid/mouse/rpc/mouse/attach.c | 43 +++++++ .../device/hid/mouse/rpc/mouse/deallocate.c | 37 ++++++ .../usb/device/hid/mouse/rpc/mouse/detach.c | 37 ++++++ bolthur/server/usb/device/hub/main.c | 4 +- build-aux/m4/flag.m4 | 4 +- config/ini/raspi/bcm2709/stage3.ini | 5 - 34 files changed, 943 insertions(+), 50 deletions(-) create mode 100644 bolthur/library/hid/Makefile.am create mode 100644 bolthur/library/hid/hid.c create mode 100644 bolthur/library/hid/hid.h create mode 100644 bolthur/server/usb/device/hid/hid/global.h create mode 100644 bolthur/server/usb/device/hid/keyboard/global.h create mode 100644 bolthur/server/usb/device/hid/keyboard/rpc.h create mode 100644 bolthur/server/usb/device/hid/keyboard/rpc/init.c create mode 100644 bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c create mode 100644 bolthur/server/usb/device/hid/keyboard/rpc/keyboard/deallocate.c create mode 100644 bolthur/server/usb/device/hid/keyboard/rpc/keyboard/detach.c create mode 100644 bolthur/server/usb/device/hid/mouse/global.h create mode 100644 bolthur/server/usb/device/hid/mouse/rpc.h create mode 100644 bolthur/server/usb/device/hid/mouse/rpc/init.c create mode 100644 bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c create mode 100644 bolthur/server/usb/device/hid/mouse/rpc/mouse/deallocate.c create mode 100644 bolthur/server/usb/device/hid/mouse/rpc/mouse/detach.c diff --git a/bolthur/kernel/lib/kasan/kasan.c b/bolthur/kernel/lib/kasan/kasan.c index a1f736f6..4fe1377b 100644 --- a/bolthur/kernel/lib/kasan/kasan.c +++ b/bolthur/kernel/lib/kasan/kasan.c @@ -25,6 +25,9 @@ #include "../../debug/debug.h" #include "../../mm/virt.h" +uintptr_t kasan_shadow_memory_start = 0; +uintptr_t kasan_shadow_memory_end = 0; + /** * @fn uintptr_t kasan_get_poisoned_shadow_address(uintptr_t, size_t) * @brief Wrapper to get poisoned shadow address @@ -91,6 +94,11 @@ void kasan_poison_shadow( const size_t shadow_length = shadow_end - shadow_start; // perform map if set if ( map ) { + // set start if not set + if ( kasan_shadow_memory_start == 0 ) { + kasan_shadow_memory_start = ROUND_DOWN_TO_FULL_PAGE( shadow_start ); + } + // map it for ( uintptr_t map_addr = ROUND_DOWN_TO_FULL_PAGE( shadow_start ); map_addr < shadow_end; @@ -107,6 +115,8 @@ void kasan_poison_shadow( VIRT_MEMORY_TYPE_NORMAL_NC, VIRT_PAGE_TYPE_READ | VIRT_PAGE_TYPE_WRITE ) ); + // adjust end + kasan_shadow_memory_end = map_addr + PAGE_SIZE; } } memset( ( void* )shadow_start, val, shadow_length ); @@ -170,6 +180,7 @@ int kasan_check_memory( * @brief Kasan init method */ void kasan_init( void ) { + // poison heap kasan_poison_shadow( HEAP_START, HEAP_MIN_SIZE, diff --git a/bolthur/kernel/lib/kasan/kasan.h b/bolthur/kernel/lib/kasan/kasan.h index a31f94dd..f2d0be91 100644 --- a/bolthur/kernel/lib/kasan/kasan.h +++ b/bolthur/kernel/lib/kasan/kasan.h @@ -24,6 +24,12 @@ #include #include "../../mm/heap.h" +#if defined( ELF32 ) + #define KASAN_SHADOW_MEMORY_OFFSET 0xC6000000 +#elif defined( ELF64 ) + #error "Shadow memory offset not defined for 64 bit" +#endif + #define KASAN_CALLER_PC ( ( uintptr_t )__builtin_return_address( 0 ) ) #define KASAN_SHADOW_SHIFT 3 @@ -37,6 +43,9 @@ #define ASAN_SHADOW_HEAP_TAIL_REDZONE_MAGIC 0xfb #define ASAN_SHADOW_HEAP_FREE_MAGIC 0xfd +extern uintptr_t kasan_shadow_memory_start; +extern uintptr_t kasan_shadow_memory_end; + typedef struct { size_t aligned_size; size_t dummy; diff --git a/bolthur/kernel/lib/kasan/print.c b/bolthur/kernel/lib/kasan/print.c index bcd07c68..243189c2 100644 --- a/bolthur/kernel/lib/kasan/print.c +++ b/bolthur/kernel/lib/kasan/print.c @@ -17,42 +17,84 @@ * along with bolthur/kernel. If not, see . */ -#include +#include "../inttypes.h" #include "../stdio.h" #include "kasan.h" +#include "../../debug/debug.h" -void kasan_print_16_bytes_no_bug(const char *prefix, const uintptr_t address) { - printf("%s%#"PRIxPTR":", prefix, address); - for (uintptr_t i = 0; i < 16; i++) printf(" %02X", *(uint8_t *)(address + i)); - printf("\r\n"); +/** + * @fn void kasan_print_16_bytes_no_bug(const char*, uintptr_t) + * @brief Print 16 bytes no bug + * @param prefix + * @param address + */ +void kasan_print_16_bytes_no_bug(const char* prefix, const uintptr_t address) { + printf( "%s%#"PRIxPTR":", prefix, address ); + for ( uintptr_t i = 0; i < 16; i++ ) { + printf( " %02"PRIx8, *( uint8_t* )( address + i ) ); + } + printf( "\r\n" ); } -void kasan_print_16_bytes_with_bug(const char* prefix, const uintptr_t address, const uintptr_t buggy_offset) { - printf("%s0x%X:", prefix, address); - for (uintptr_t i = 0; i < buggy_offset; i++) - printf(" %02"PRIx8"", *(uint8_t *)(address + i)); - printf("[%02"PRIx8"]", *(uint8_t *)(address + buggy_offset)); - if (buggy_offset < 15) - printf("%02"PRIx8, *(uint8_t *)(address + buggy_offset + 1)); - for (uintptr_t i = buggy_offset + 2; i < 16; i++) - printf(" %02"PRIx8"", *(uint8_t *)(address + i)); - printf("\r\n"); +/** + * @fn void kasan_print_16_bytes_with_bug(const char*, uintptr_t, uintptr_t) + * @brief Print 16 bytes with bug + * @param prefix + * @param address + * @param buggy_offset + */ +void kasan_print_16_bytes_with_bug( + const char* prefix, + const uintptr_t address, + const uintptr_t buggy_offset +) { + printf( "%s%#"PRIxPTR":", prefix, address ); + for ( uintptr_t i = 0; i < buggy_offset; i++ ) { + printf( " %02"PRIx8, *( uint8_t* )( address + i ) ); + } + printf( "[%02"PRIx8"]", *( uint8_t* )( address + buggy_offset ) ); + if ( buggy_offset < 15 ) { + printf( "%02"PRIx8, *( uint8_t* )( address + buggy_offset + 1 ) ); + } + for ( uintptr_t i = buggy_offset + 2; i < 16; i++ ) { + printf( " %02"PRIx8, *( uint8_t* )( address + i ) ); + } + printf( "\r\n" ); } -void kasan_print_shadow_memory( const uintptr_t addr, const uintptr_t before, const uintptr_t after ) { - uintptr_t shadow_address = KASAN_MEM_TO_SHADOW( addr ); - uintptr_t aligned_shadow = shadow_address & 0xfffffff0; - uintptr_t buggy_offset = shadow_address - aligned_shadow; +/** + * @fn void kasan_print_shadow_memory(uintptr_t, uintptr_t, uintptr_t) + * @brief Function to print shadow memory + * @param addr + * @param before + * @param after + */ +void kasan_print_shadow_memory( + const uintptr_t addr, + uintptr_t before, + uintptr_t after +) { + const uintptr_t shadow_address = KASAN_MEM_TO_SHADOW( addr ); + const uintptr_t aligned_shadow = shadow_address & 0xfffffff0; + const uintptr_t buggy_offset = shadow_address - aligned_shadow; printf( "[KASan] Shadow bytes around the buggy address %#"PRIxPTR" (shadow %#"PRIxPTR"):\r\n", addr, shadow_address ); - + const uintptr_t max_before = shadow_address - kasan_shadow_memory_start; + const uintptr_t max_after = kasan_shadow_memory_start - 1 - shadow_address; + if ( before * 16 > max_before ) { + before = max_before / 16; + } + if ( after * 16 > max_after ) { + after = max_after / 16; + } + // print memory before for (uintptr_t i = before; i > 0; i--) { kasan_print_16_bytes_no_bug("[KASan] ", aligned_shadow - i * 16); } - + // print buggy memory kasan_print_16_bytes_with_bug("[KASan] =>", aligned_shadow, buggy_offset); - + // print memory after for (uintptr_t i = 1; i <= after; i++) { kasan_print_16_bytes_no_bug("[KASan] ", aligned_shadow + i * 16); } @@ -78,5 +120,5 @@ void kasan_bug_report( printf( "[KASan] ===================================================\r\n" ); printf( "[KASan] ERROR: Invalid memory access: address %#"PRIxPTR", size %zu, write %d, ip %#"PRIxPTR"\r\n", addr, size, write ? 1 : 0, pc ); - //kasan_print_shadow_memory( buggy_address, 3, 3 ); + kasan_print_shadow_memory( buggy_address, 3, 3 ); } diff --git a/bolthur/kernel/mm/heap.h b/bolthur/kernel/mm/heap.h index f3dc35ad..b92f575a 100644 --- a/bolthur/kernel/mm/heap.h +++ b/bolthur/kernel/mm/heap.h @@ -29,13 +29,6 @@ #define HEAP_MAX_SIZE 0xFFFFFFF #define HEAP_MIN_SIZE 0x10000 #define HEAP_EXTENSION 0x1000 - #if defined( HAS_SANITIZER ) - #define KASAN_SHADOW_MEMORY_OFFSET 0xC6000000 - #define KASAN_SHADOW_MEMORY_MAP_OFFSET 0x10000000 - #define KASAN_SHADOW_MEMORY_START 0xE0000000 - #define KASAN_SHADOW_MEMORY_MIN_SIZE 0x10000 - #define KASAN_SHADOW_MEMORY_MAX_SIZE 0xFFFFFFF - #endif #elif defined( ELF64 ) #error "Heap not ready for x64" #endif diff --git a/bolthur/kernel/mm/shared.c b/bolthur/kernel/mm/shared.c index a23f3c66..af8b8b71 100644 --- a/bolthur/kernel/mm/shared.c +++ b/bolthur/kernel/mm/shared.c @@ -55,7 +55,7 @@ static int32_t lookup_process( const list_item_t* a, const void* b ) { /** * @fn void cleanup_process(list_item_t*) - * @brief Helper to cleanup process list + * @brief Helper to clean up process list * * @param a */ diff --git a/bolthur/library/Makefile.am b/bolthur/library/Makefile.am index eaa5465c..dee98ffc 100644 --- a/bolthur/library/Makefile.am +++ b/bolthur/library/Makefile.am @@ -1,4 +1,4 @@ ACLOCAL_AMFLAGS = -I ../../build-aux/m4 -SUBDIRS = collection framebuffer handle usb +SUBDIRS = collection framebuffer handle hid usb diff --git a/bolthur/library/configure.ac b/bolthur/library/configure.ac index e1e04f11..db11b03b 100644 --- a/bolthur/library/configure.ac +++ b/bolthur/library/configure.ac @@ -139,6 +139,7 @@ AC_CONFIG_FILES([ collection/list/Makefile framebuffer/Makefile handle/Makefile + hid/Makefile usb/Makefile ]) # FIXME: REPLACE WITH SUBMODULE WHEN MOVING TO OWN REPO diff --git a/bolthur/library/hid/Makefile.am b/bolthur/library/hid/Makefile.am new file mode 100644 index 00000000..c76c88fe --- /dev/null +++ b/bolthur/library/hid/Makefile.am @@ -0,0 +1,6 @@ + +AM_CFLAGS = -DPROGRAM_NAME=\"bolthur/libhid\" + +noinst_LTLIBRARIES = libhid.la +libhid_la_SOURCES = \ + hid.c diff --git a/bolthur/library/hid/hid.c b/bolthur/library/hid/hid.c new file mode 100644 index 00000000..a099ecfc --- /dev/null +++ b/bolthur/library/hid/hid.c @@ -0,0 +1,108 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +#include +// local includes +#include "hid.h" +// server includes +#include "../../server/libusbd.h" + +static int fd_hid = -1; + +/** + * @fn int hid_init( void ) + * @brief HID library init + * @return + */ +int hid_init( void ) { + // handle already initialized + if ( fd_hid != -1 ) { + return 0; + } + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Opening %s\r\n", USBD_DEVICE_PATH ) + #endif + // open handle + fd_hid = open( HID_DEVICE_PATH, O_RDWR ); + // handle error + if ( fd_hid == -1 ) { + return errno; + } + // return success + return 0; +} + +/** + * @fn int hid_register_handler(libhid_interface_type_t) + * @brief Method to attach a new discovered device + * @param type + * @return + */ +int hid_register_handler( const libhid_interface_type_t type ) { + const pid_t pid = getpid(); + // debug message + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Registering pid %d for type %d\r\n", pid, type ) + #endif + // allocate device + hid_register_device_handler_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->type = type; + request->handler = pid; + // perform request + const int result = ioctl( + fd_hid, + IOCTL_BUILD_REQUEST( + HID_REGISTER_HANDLER, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // free request + free( request ); + // return success + return 0; +} diff --git a/bolthur/library/hid/hid.h b/bolthur/library/hid/hid.h new file mode 100644 index 00000000..aa01b11d --- /dev/null +++ b/bolthur/library/hid/hid.h @@ -0,0 +1,28 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _HID_H +#define _HID_H + +#include "../../server/libusb.h" + +int hid_init( void ); +int hid_register_handler( libhid_interface_type_t ); + +#endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index edcc6ba7..41ee9039 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -350,6 +350,11 @@ typedef enum { LIBUSB_TRANSFER_ERROR_PROCESSING = 1 << 10, } libusb_transfer_error_t; +typedef enum { + LIBHID_INTERFACE_TYPE_MOUSE = 2, + LIBHID_INTERFACE_TYPE_KEYBOARD = 6, +} libhid_interface_type_t; + typedef struct { uint32_t device_driver; uint32_t data_size; diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index 9086d36a..e8aebda8 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -26,6 +26,9 @@ // device paths #define USBD_DEVICE_PATH "/dev/usb/usbd" #define HUB_DEVICE_PATH "/dev/usb/hub" +#define HID_DEVICE_PATH "/dev/usb/hid" +#define KEYBOARD_DEVICE_PATH "/dev/usb/keyboard" +#define MOUSE_DEVICE_PATH "/dev/usb/mouse" // generic rpc #define GENERIC_ATTACH RPC_CUSTOM_START @@ -60,6 +63,17 @@ typedef struct { uint32_t interface_number; } usb_generic_attach_t; +// hid rpc structures +typedef struct { + libhid_interface_type_t type; + pid_t handler; +} hid_register_device_handler_t; + +typedef struct { + libhid_interface_type_t type; + pid_t handler; +} hid_unregister_device_handler_t; + // usbd rpc structures typedef struct { libusb_interface_class_t type; diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index 1b1a1bd5..b913bf5d 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -2,6 +2,10 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/hid\" bin_PROGRAMS = hid +hid_DEPENDENCIES = \ + ${abs_top_builddir}/../library/usb/libusb.la +hid_LDADD = \ + ${abs_top_builddir}/../library/usb/libusb.la hid_SOURCES = \ rpc/handler/register.c \ rpc/handler/unregister.c \ diff --git a/bolthur/server/usb/device/hid/hid/global.h b/bolthur/server/usb/device/hid/hid/global.h new file mode 100644 index 00000000..f13b5a5c --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/global.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include + +extern pid_t allowed_rpc_origin; + +#endif diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c index c6035703..c616dd64 100644 --- a/bolthur/server/usb/device/hid/hid/main.c +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -20,6 +20,14 @@ #include #include #include "rpc.h" +#include "../../../../libhelper.h" +#include "../../../../libusbd.h" +#include "../../../../../library/usb/usb.h" + +/** + * @brief Allowed rpc origin + */ +pid_t allowed_rpc_origin; /** * @fn int main(int, char*[]) @@ -37,7 +45,49 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } - // print something - STARTUP_PRINT( "usb hid hid processing!\r\n" ) - return -1; + // initialize usb library + STARTUP_PRINT( "Setup usb library\r\n" ) + int result = usb_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); + return -1; + } + + // query allowed rpc origin + allowed_rpc_origin = get_file_handler( USBD_DEVICE_PATH ); + if ( -1 == allowed_rpc_origin ) { + STARTUP_PRINT( "Unable to get handler id of %s\r\n", USBD_DEVICE_PATH ) + return -1; + } + + // registering handler + STARTUP_PRINT( "Registering handler at usbd\r\n" ) + result = usb_register_handler( LIBUSB_INTERFACE_CLASS_HUB ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to register handler at usbd\r\n" ) + return -1; + } + + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); + + // add device file + STARTUP_PRINT( "Sending device to vfs\r\n" ) + uint32_t device_info[] = { + GENERIC_ATTACH, + GENERIC_DETACH, + GENERIC_DEALLOCATE, + HID_REGISTER_HANDLER, + HID_UNREGISTER_HANDLER, + }; + if ( !dev_add_file( HID_DEVICE_PATH, device_info, 5 ) ) { + STARTUP_PRINT( "Unable to add dev usbd\r\n" ) + return -1; + } + + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/usb/device/hid/keyboard/Makefile.am b/bolthur/server/usb/device/hid/keyboard/Makefile.am index e6f16990..ac61c0f1 100644 --- a/bolthur/server/usb/device/hid/keyboard/Makefile.am +++ b/bolthur/server/usb/device/hid/keyboard/Makefile.am @@ -2,6 +2,16 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/keyboard\" bin_PROGRAMS = keyboard +keyboard_DEPENDENCIES = \ + ${abs_top_builddir}/../library/hid/libhid.la \ + ${abs_top_builddir}/../library/usb/libusb.la +keyboard_LDADD = \ + ${abs_top_builddir}/../library/hid/libhid.la \ + ${abs_top_builddir}/../library/usb/libusb.la keyboard_SOURCES = \ + rpc/keyboard/attach.c \ + rpc/keyboard/deallocate.c \ + rpc/keyboard/detach.c \ + rpc/init.c \ main.c keyboard_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/keyboard/global.h b/bolthur/server/usb/device/hid/keyboard/global.h new file mode 100644 index 00000000..f13b5a5c --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/global.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include + +extern pid_t allowed_rpc_origin; + +#endif diff --git a/bolthur/server/usb/device/hid/keyboard/main.c b/bolthur/server/usb/device/hid/keyboard/main.c index dfd3ab70..788cc141 100644 --- a/bolthur/server/usb/device/hid/keyboard/main.c +++ b/bolthur/server/usb/device/hid/keyboard/main.c @@ -19,6 +19,16 @@ #include #include +#include "rpc.h" +#include "../../../../libhelper.h" +#include "../../../../libusbd.h" +#include "../../../../../library/usb/usb.h" +#include "../../../../../library/hid/hid.h" + +/** + * @brief Allowed rpc origin + */ +pid_t allowed_rpc_origin; /** * @fn int main(int, char*[]) @@ -29,7 +39,62 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print something - STARTUP_PRINT( "usb hid keyboard processing!\r\n" ) - return -1; + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); + return -1; + } + + // initialize usb library + STARTUP_PRINT( "Setup usb library\r\n" ) + int result = usb_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); + return -1; + } + + // initialize hid library + STARTUP_PRINT( "Setup hid library\r\n" ) + result = hid_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); + return -1; + } + + // query allowed rpc origin + allowed_rpc_origin = get_file_handler( HID_DEVICE_PATH ); + if ( -1 == allowed_rpc_origin ) { + STARTUP_PRINT( "Unable to get handler id of %s\r\n", USBD_DEVICE_PATH ) + return -1; + } + + // registering handler + STARTUP_PRINT( "Registering handler at hid\r\n" ) + result = hid_register_handler( LIBHID_INTERFACE_TYPE_KEYBOARD ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to register handler at hid\r\n" ) + return -1; + } + + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); + + // add device file + STARTUP_PRINT( "Sending device to vfs\r\n" ) + uint32_t device_info[] = { + GENERIC_ATTACH, + GENERIC_DETACH, + GENERIC_DEALLOCATE, + }; + if ( !dev_add_file( KEYBOARD_DEVICE_PATH, device_info, 3 ) ) { + STARTUP_PRINT( "Unable to add dev usbd\r\n" ) + return -1; + } + + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/usb/device/hid/keyboard/rpc.h b/bolthur/server/usb/device/hid/keyboard/rpc.h new file mode 100644 index 00000000..cba85dcb --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/rpc.h @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +void rpc_keyboard_attach( size_t, pid_t, size_t, size_t ); +void rpc_keyboard_deallocate( size_t, pid_t, size_t, size_t ); +void rpc_keyboard_detach( size_t, pid_t, size_t, size_t ); +bool rpc_init( void ); + +#endif diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/init.c b/bolthur/server/usb/device/hid/keyboard/rpc/init.c new file mode 100644 index 00000000..f8418f84 --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/rpc/init.c @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include "../rpc.h" +#include "../../../../../libusbd.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + // register handler keyboard attach + bolthur_rpc_bind( GENERIC_ATTACH, rpc_keyboard_attach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register attach handler!\r\n" ) + return false; + } + // register handler detach + bolthur_rpc_bind( GENERIC_DETACH, rpc_keyboard_detach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register detach handler!\r\n" ) + return false; + } + // register handler deallocate + bolthur_rpc_bind( GENERIC_DEALLOCATE, rpc_keyboard_deallocate, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register deallocate handler!\r\n" ) + return false; + } + return true; +} diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c new file mode 100644 index 00000000..e2cf8f9c --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +#include "../../../../../../libusbd.h" +#include "../../../../../../../library/usb/usb.h" + +/** + * @fn void rpc_keyboard_attach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler attach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_keyboard_attach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/deallocate.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/deallocate.c new file mode 100644 index 00000000..5f313111 --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/deallocate.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_keyboard_deallocate(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler deallocate + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_keyboard_deallocate( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/detach.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/detach.c new file mode 100644 index 00000000..59402cdd --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/detach.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_keyboard_detach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler detach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_keyboard_detach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/mouse/Makefile.am b/bolthur/server/usb/device/hid/mouse/Makefile.am index 80717fee..6362e919 100644 --- a/bolthur/server/usb/device/hid/mouse/Makefile.am +++ b/bolthur/server/usb/device/hid/mouse/Makefile.am @@ -2,6 +2,16 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/mouse\" bin_PROGRAMS = mouse +mouse_DEPENDENCIES = \ + ${abs_top_builddir}/../library/hid/libhid.la \ + ${abs_top_builddir}/../library/usb/libusb.la +mouse_LDADD = \ + ${abs_top_builddir}/../library/hid/libhid.la \ + ${abs_top_builddir}/../library/usb/libusb.la mouse_SOURCES = \ + rpc/mouse/attach.c \ + rpc/mouse/deallocate.c \ + rpc/mouse/detach.c \ + rpc/init.c \ main.c mouse_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/mouse/global.h b/bolthur/server/usb/device/hid/mouse/global.h new file mode 100644 index 00000000..f13b5a5c --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/global.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include + +extern pid_t allowed_rpc_origin; + +#endif diff --git a/bolthur/server/usb/device/hid/mouse/main.c b/bolthur/server/usb/device/hid/mouse/main.c index 114d6f66..bf0da09a 100644 --- a/bolthur/server/usb/device/hid/mouse/main.c +++ b/bolthur/server/usb/device/hid/mouse/main.c @@ -19,6 +19,16 @@ #include #include +#include "rpc.h" +#include "../../../../libhelper.h" +#include "../../../../libusbd.h" +#include "../../../../../library/usb/usb.h" +#include "../../../../../library/hid/hid.h" + +/** + * @brief Allowed rpc origin + */ +pid_t allowed_rpc_origin; /** * @fn int main(int, char*[]) @@ -29,7 +39,62 @@ * @return */ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { - // print something - STARTUP_PRINT( "usb hid mouse processing!\r\n" ) - return -1; + // register rpc + STARTUP_PRINT( "Setup rpc handler\r\n" ) + if ( !rpc_init() ) { + STARTUP_PRINT( "Unable to bind rpc handler\r\n" ); + return -1; + } + + // initialize usb library + STARTUP_PRINT( "Setup usb library\r\n" ) + int result = usb_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); + return -1; + } + + // initialize hid library + STARTUP_PRINT( "Setup hid library\r\n" ) + result = hid_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); + return -1; + } + + // query allowed rpc origin + allowed_rpc_origin = get_file_handler( HID_DEVICE_PATH ); + if ( -1 == allowed_rpc_origin ) { + STARTUP_PRINT( "Unable to get handler id of %s\r\n", USBD_DEVICE_PATH ) + return -1; + } + + // registering handler + STARTUP_PRINT( "Registering handler at hid\r\n" ) + result = hid_register_handler( LIBHID_INTERFACE_TYPE_MOUSE ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to register handler at hid\r\n" ) + return -1; + } + + // enable rpc + STARTUP_PRINT( "Enable rpc\r\n" ) + _syscall_rpc_set_ready( true ); + + // add device file + STARTUP_PRINT( "Sending device to vfs\r\n" ) + uint32_t device_info[] = { + GENERIC_ATTACH, + GENERIC_DETACH, + GENERIC_DEALLOCATE, + }; + if ( !dev_add_file( MOUSE_DEVICE_PATH, device_info, 3 ) ) { + STARTUP_PRINT( "Unable to add dev usbd\r\n" ) + return -1; + } + + // wait for rpc + STARTUP_PRINT( "Wait for rpc\r\n" ) + bolthur_rpc_wait_block(); + return 0; } diff --git a/bolthur/server/usb/device/hid/mouse/rpc.h b/bolthur/server/usb/device/hid/mouse/rpc.h new file mode 100644 index 00000000..72f5498a --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/rpc.h @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _RPC_H +#define _RPC_H + +#include +#include + +void rpc_mouse_attach( size_t, pid_t, size_t, size_t ); +void rpc_mouse_deallocate( size_t, pid_t, size_t, size_t ); +void rpc_mouse_detach( size_t, pid_t, size_t, size_t ); +bool rpc_init( void ); + +#endif diff --git a/bolthur/server/usb/device/hid/mouse/rpc/init.c b/bolthur/server/usb/device/hid/mouse/rpc/init.c new file mode 100644 index 00000000..4bba2d92 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/rpc/init.c @@ -0,0 +1,50 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include "../rpc.h" +#include "../../../../../libusbd.h" + +/** + * @fn bool rpc_init(void) + * @brief Init rpc handler method + * @return + */ +bool rpc_init( void ) { + // register handler mouse attach + bolthur_rpc_bind( GENERIC_ATTACH, rpc_mouse_attach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register attach handler!\r\n" ) + return false; + } + // register handler detach + bolthur_rpc_bind( GENERIC_DETACH, rpc_mouse_detach, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register detach handler!\r\n" ) + return false; + } + // register handler deallocate + bolthur_rpc_bind( GENERIC_DEALLOCATE, rpc_mouse_deallocate, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register deallocate handler!\r\n" ) + return false; + } + return true; +} diff --git a/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c new file mode 100644 index 00000000..43d6ebc7 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +#include "../../../../../../libusbd.h" +#include "../../../../../../../library/usb/usb.h" + +/** + * @fn void rpc_mouse_attach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler attach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_mouse_attach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/mouse/rpc/mouse/deallocate.c b/bolthur/server/usb/device/hid/mouse/rpc/mouse/deallocate.c new file mode 100644 index 00000000..d9e589d1 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/rpc/mouse/deallocate.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_mouse_deallocate(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler deallocate + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_mouse_deallocate( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hid/mouse/rpc/mouse/detach.c b/bolthur/server/usb/device/hid/mouse/rpc/mouse/detach.c new file mode 100644 index 00000000..a2921e64 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/rpc/mouse/detach.c @@ -0,0 +1,37 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include "../../rpc.h" + +/** + * @fn void rpc_mouse_detach(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler detach + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_mouse_detach( + [[maybe_unused]] size_t type, + [[maybe_unused]] pid_t origin, + [[maybe_unused]] size_t data_info, + [[maybe_unused]] size_t response_info +) { +} diff --git a/bolthur/server/usb/device/hub/main.c b/bolthur/server/usb/device/hub/main.c index 496c2bc9..5d4eae2b 100644 --- a/bolthur/server/usb/device/hub/main.c +++ b/bolthur/server/usb/device/hub/main.c @@ -26,8 +26,6 @@ // library includes #include "../../../libhelper.h" #include "../../../libusbd.h" -#include "../../../libusbd.h" -#include "../../../libusbd.h" #include "../../../../library/usb/usb.h" /** @@ -51,7 +49,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } - // intialize usb library + // initialize usb library STARTUP_PRINT( "Setup usb library\r\n" ) int result = usb_init(); if ( 0 != result ) { diff --git a/build-aux/m4/flag.m4 b/build-aux/m4/flag.m4 index e14681bc..729ce3cf 100644 --- a/build-aux/m4/flag.m4 +++ b/build-aux/m4/flag.m4 @@ -114,7 +114,9 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_FLAG], [ # debug parameter AS_IF([test "x$with_debug_symbols" == "xyes"], [ # debug symbols and sanitizer - AX_APPEND_COMPILE_FLAGS([-g -Og -fsanitize=undefined -fsanitize=kernel-address]) + AX_APPEND_COMPILE_FLAGS([-g -Og]) + AX_APPEND_COMPILE_FLAGS([-fsanitize=undefined]) + AX_APPEND_COMPILE_FLAGS([-fsanitize=kernel-address]) ]) # optimization level case "${with_optimization_level}" in diff --git a/config/ini/raspi/bcm2709/stage3.ini b/config/ini/raspi/bcm2709/stage3.ini index e5e38c70..04a6c541 100644 --- a/config/ini/raspi/bcm2709/stage3.ini +++ b/config/ini/raspi/bcm2709/stage3.ini @@ -23,11 +23,6 @@ path = /server/usb/mouse device = /dev/usb/mouse early = false -[storage] -path = /server/usb/storage -device = /dev/usb/storage -early = false - [hcd] path = /server/usb/hcd device = /dev/usb/hcd From e3419a1915d7b9db07f6099ee141a1160a6b4745 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Tue, 29 Jul 2025 19:05:17 +0200 Subject: [PATCH 025/144] - Added avl dependency to hid - Created handler management functions - Implemented register and unregister handler - Fixed defined checks in libhid - Fixed register of usbd handler in hid --- bolthur/library/hid/hid.c | 6 +- bolthur/server/usb/device/hid/hid/Makefile.am | 7 +- bolthur/server/usb/device/hid/hid/handler.c | 199 ++++++++++++++++++ bolthur/server/usb/device/hid/hid/handler.h | 39 ++++ bolthur/server/usb/device/hid/hid/main.c | 14 +- .../usb/device/hid/hid/rpc/handler/register.c | 39 +++- .../device/hid/hid/rpc/handler/unregister.c | 39 +++- bolthur/server/usb/usbd/usbd.c | 22 +- 8 files changed, 353 insertions(+), 12 deletions(-) create mode 100644 bolthur/server/usb/device/hid/hid/handler.c create mode 100644 bolthur/server/usb/device/hid/hid/handler.h diff --git a/bolthur/library/hid/hid.c b/bolthur/library/hid/hid.c index a099ecfc..a012885d 100644 --- a/bolthur/library/hid/hid.c +++ b/bolthur/library/hid/hid.c @@ -62,7 +62,7 @@ int hid_init( void ) { int hid_register_handler( const libhid_interface_type_t type ) { const pid_t pid = getpid(); // debug message - #if defined( LIBUSB_ENABLE_DEBUG ) + #if defined( LIBHID_ENABLE_DEBUG ) STARTUP_PRINT( "Registering pid %d for type %d\r\n", pid, type ) #endif // allocate device @@ -70,7 +70,7 @@ int hid_register_handler( const libhid_interface_type_t type ) { // handle error if ( ! request ) { // debug output - #if defined( LIBUSB_ENABLE_DEBUG ) + #if defined( LIBHID_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to allocate request\r\n" ) #endif // return nomem @@ -94,7 +94,7 @@ int hid_register_handler( const libhid_interface_type_t type ) { // handle ioctl error if ( -1 == result ) { // debug output - #if defined( LIBUSB_ENABLE_DEBUG ) + #if defined( LIBHID_ENABLE_DEBUG ) STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); #endif // free request diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index b913bf5d..c13b51bd 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -3,9 +3,11 @@ AM_CFLAGS = -DPROGRAM_NAME=\"usb/device/hid/hid\" bin_PROGRAMS = hid hid_DEPENDENCIES = \ - ${abs_top_builddir}/../library/usb/libusb.la + ${abs_top_builddir}/../library/usb/libusb.la \ + ${abs_top_builddir}/../library/collection/avl/libavl.la hid_LDADD = \ - ${abs_top_builddir}/../library/usb/libusb.la + ${abs_top_builddir}/../library/usb/libusb.la \ + ${abs_top_builddir}/../library/collection/avl/libavl.la hid_SOURCES = \ rpc/handler/register.c \ rpc/handler/unregister.c \ @@ -13,5 +15,6 @@ hid_SOURCES = \ rpc/hid/deallocate.c \ rpc/hid/detach.c \ rpc/init.c \ + handler.c \ main.c hid_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/hid/handler.c b/bolthur/server/usb/device/hid/hid/handler.c new file mode 100644 index 00000000..fb9e609e --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/handler.c @@ -0,0 +1,199 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include +#include +#include +#include "handler.h" +#include "../../../../../library/collection/avl/avl.h" + +static avl_tree_t* management_tree; + + +/** + * @fn int32_t compare_container(const avl_node_t*, const avl_node_t*) + * @brief Compare handle callback necessary for avl tree insert / delete + * + * @param node_a + * @param node_b + * @return + */ +static int32_t compare_container( + const avl_node_t* node_a, + const avl_node_t* node_b +) { + const pid_container_t* container_a = PID_HANDLER_GET_ENTRY( node_a ); + const pid_container_t* container_b = PID_HANDLER_GET_ENTRY( node_b ); + // return 0 if equal + if ( container_a->handler == container_b->handler ) { + return 0; + } + // return -1 or 1 depending on what is greater + return container_a->handler > container_b->handler ? -1 : 1; +} + +/** + * @fn int32_t lookup_container(const avl_node_t*, const void*) + * @brief Lookup handle callback necessary for avl tree search operations + * + * @param node + * @param value + * @return + */ +static int32_t lookup_container( + const avl_node_t* node, + const void* value +) { + pid_t handler = ( pid_t )value; + pid_container_t* container = PID_HANDLER_GET_ENTRY( node ); + // return 0 if equal + if ( container->handler == handler ) { + return 0; + } + // return -1 or 1 depending on what is greater + return container->handler > handler ? -1 : 1; +} + +/** + * @fn void cleanup_container(avl_node_t*) + * @brief handle cleanup + * + * @param node + */ +static void cleanup_container( avl_node_t* node ) { + pid_container_t* item = PID_HANDLER_GET_ENTRY( node ); + // free item + free( item ); +} + +/** + * @fn int handler_init(void) + * @brief Wrapper to init handler management + * @return + */ +int handler_init( void ) { + // generate tree + management_tree = avl_create_tree( + compare_container, + lookup_container, + cleanup_container + ); + // handle error + if ( ! management_tree ) { + return ENOMEM; + } + // return success + return 0; +} + +/** + * @fn int handler_register(libhid_interface_type_t, pid_t) + * @brief Method to register a handler + * @param type + * @param handler + * @return + */ +int handler_register( const libhid_interface_type_t type, const pid_t handler ) { + // validate + if ( ! management_tree ) { + return EINVAL; + } + // try to find possible handler + const avl_node_t* found = avl_find_by_data( management_tree, ( void* )handler ); + // handle found + if ( found ) { + return EINVAL; + } + // allocate new container + pid_container_t* item = malloc( sizeof( *item ) ); + if ( ! item ) { + return ENOMEM; + } + // clear out + memset( item, 0, sizeof( *item ) ); + // pure in data + item->handler = handler; + // prepare node + avl_prepare_node( &item->node, ( void* )type ); + // insert into tree + if ( ! avl_insert_by_node( management_tree, &item->node ) ) { + free( item ); + return EAGAIN; + } + // return success + return 0; +} + +/** + * @fn int handler_unregister(libhid_interface_type_t, pid_t) + * @brief Unregister a handler + * @param type + * @param handler + * @return + */ +int handler_unregister( const libhid_interface_type_t type, const pid_t handler ) { + // validate + if ( ! management_tree ) { + return EINVAL; + } + // try to find possible handler + avl_node_t* found = avl_find_by_data( management_tree, ( void* )type ); + // handle not found => return success + if ( ! found ) { + return 0; + } + // compare handlers + pid_container_t* item = PID_HANDLER_GET_ENTRY( found ); + // handle no matcj + if ( item->handler != handler ) { + return EINVAL; + } + // return node + avl_remove_by_node( management_tree, found ); + // cleanup node + free( item ); + // return success + return 0; +} + +/** + * @fn int handler_get(libhid_interface_type_t, pid_t*) + * @brief Get a handler + * @param type + * @param handler + * @return + */ +int handler_get( const libhid_interface_type_t type, pid_t* handler ) { + // validate + if ( ! handler || ! management_tree ) { + return EINVAL; + } + // try to find possible handler + const avl_node_t* found = avl_find_by_data( management_tree, ( void* )type ); + // handle not found + if ( ! found ) { + *handler = 0; + // handle found + } else { + pid_container_t* container = PID_HANDLER_GET_ENTRY( found ); + *handler = container->handler; + } + // return success + return 0; +} diff --git a/bolthur/server/usb/device/hid/hid/handler.h b/bolthur/server/usb/device/hid/hid/handler.h new file mode 100644 index 00000000..989013f6 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/handler.h @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _HANDLER_H +#define _HANDLER_H + +#include "../../../../libusb.h" +#include "../../../../../library/collection/avl/avl.h" + +typedef struct { + avl_node_t node; + pid_t handler; +} pid_container_t; + +#define PID_HANDLER_GET_ENTRY( n ) \ + ( pid_container_t* )( ( uint8_t* )n - offsetof( pid_container_t, node ) ) + +int handler_init( void ); +int handler_register( libhid_interface_type_t, pid_t ); +int handler_unregister( libhid_interface_type_t, pid_t ); +int handler_get( libhid_interface_type_t, pid_t* ); + +#endif diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c index c616dd64..548389fa 100644 --- a/bolthur/server/usb/device/hid/hid/main.c +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -19,6 +19,8 @@ #include #include + +#include "handler.h" #include "rpc.h" #include "../../../../libhelper.h" #include "../../../../libusbd.h" @@ -45,9 +47,17 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { return -1; } + // initialize handler management + STARTUP_PRINT( "Setup handler management\r\n" ) + int result = handler_init(); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to init handler management: %s\r\n", strerror( result ) ) + return -1; + } + // initialize usb library STARTUP_PRINT( "Setup usb library\r\n" ) - int result = usb_init(); + result = usb_init(); if ( 0 != result ) { STARTUP_PRINT( "Unable to bind usb library: %s\r\n", strerror( result ) ); return -1; @@ -62,7 +72,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // registering handler STARTUP_PRINT( "Registering handler at usbd\r\n" ) - result = usb_register_handler( LIBUSB_INTERFACE_CLASS_HUB ); + result = usb_register_handler( LIBUSB_INTERFACE_CLASS_HID ); if ( 0 != result ) { STARTUP_PRINT( "Unable to register handler at usbd\r\n" ) return -1; diff --git a/bolthur/server/usb/device/hid/hid/rpc/handler/register.c b/bolthur/server/usb/device/hid/hid/rpc/handler/register.c index 3fa12bd5..71f57f54 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/handler/register.c +++ b/bolthur/server/usb/device/hid/hid/rpc/handler/register.c @@ -22,6 +22,8 @@ #include // local includes #include "../../rpc.h" +#include "../../handler.h" +#include "../../../../../../libusbd.h" /** * @fn void rpc_handler_register(size_t, pid_t, size_t, size_t) @@ -35,8 +37,41 @@ */ void rpc_handler_register( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info ) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + const hid_register_device_handler_t* message = ( hid_register_device_handler_t* )request->container; + // register handler + const int result = handler_register( message->type, message->handler ); + // handle error + if ( 0 != result ) { + error.status = -result; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // return success without data + error.status = 0; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + free( request ); } diff --git a/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c b/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c index 1aa4afc3..2aa3fc3e 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c +++ b/bolthur/server/usb/device/hid/hid/rpc/handler/unregister.c @@ -21,7 +21,9 @@ #include #include // local includes +#include "handler.h" #include "../../rpc.h" +#include "../../../../../../libusbd.h" /** * @fn void rpc_handler_unregister(size_t, pid_t, size_t, size_t) @@ -35,8 +37,41 @@ */ void rpc_handler_unregister( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info ) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + const hid_unregister_device_handler_t* message = ( hid_unregister_device_handler_t* )request->container; + // unregister handler + const int result = handler_unregister( message->type, message->handler ); + // handle error + if ( 0 != result ) { + error.status = -result; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // return success + error.status = 0; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + free( request ); } diff --git a/bolthur/server/usb/usbd/usbd.c b/bolthur/server/usb/usbd/usbd.c index c2d604dd..d4588083 100644 --- a/bolthur/server/usb/usbd/usbd.c +++ b/bolthur/server/usb/usbd/usbd.c @@ -1201,7 +1201,6 @@ libusb_device_t* usbd_get_root_hub( void ) { return head; } - /** * @fn int usbd_init(void) * @brief Method to init usbd @@ -1269,6 +1268,13 @@ int usbd_init_handler( void ) { return 0; } +/** + * @fn int usbd_register_handler(libusb_interface_class_t, pid_t) + * @brief Method to register a handöer + * @param type + * @param handler + * @return + */ int usbd_register_handler( const libusb_interface_class_t type, const pid_t handler ) { // handle not initialized if ( ! class_handler ) { @@ -1294,6 +1300,13 @@ int usbd_register_handler( const libusb_interface_class_t type, const pid_t hand return 0; } +/** + * @fn int usbd_unregister_handler(libusb_interface_class_t, pid_t) + * @brief Unregister a handler + * @param type + * @param handler + * @return + */ int usbd_unregister_handler( const libusb_interface_class_t type, const pid_t handler ) { // handle not initialized if ( ! class_handler ) { @@ -1319,6 +1332,13 @@ int usbd_unregister_handler( const libusb_interface_class_t type, const pid_t ha return 0; } +/** + * @fn int usbd_get_handler(libusb_interface_class_t, pid_t*) + * @brief Method to get a bound handler + * @param type + * @param handler + * @return + */ int usbd_get_handler( const libusb_interface_class_t type, pid_t* handler ) { // handle not initialized if ( ! class_handler ) { From 65339eaefdc7d83ebad5bd32af84d0b4650c54ad Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Wed, 30 Jul 2025 18:41:25 +0200 Subject: [PATCH 026/144] - Added options to enable ubsan and / or asan instead of binding it to debug symbols - Started working on hid attach logic - Added new rpc call to get configuration data from usbd by device number - Added new rpc call to get device status from usbd by device number - Created usb wrapper to fetch configuration data - Created usb wrapper to fetch device status --- bolthur/application/configure.ac | 18 ++ bolthur/kernel/configure.ac | 18 ++ bolthur/library/configure.ac | 18 ++ bolthur/library/usb/usb.c | 164 +++++++++++++ bolthur/library/usb/usb.h | 2 + bolthur/server/configure.ac | 18 ++ bolthur/server/libusb.h | 53 ++++ bolthur/server/libusbd.h | 15 +- .../usb/device/hid/hid/rpc/hid/attach.c | 227 +++++++++++++++++- bolthur/server/usb/usbd/Makefile.am | 2 + bolthur/server/usb/usbd/call.c | 2 +- bolthur/server/usb/usbd/main.c | 4 +- bolthur/server/usb/usbd/rpc.h | 2 + .../server/usb/usbd/rpc/get/configuration.c | 127 ++++++++++ bolthur/server/usb/usbd/rpc/get/status.c | 104 ++++++++ bolthur/server/usb/usbd/rpc/init.c | 12 + build-aux/m4/flag.m4 | 4 + build-aux/m4/host.m4 | 2 +- configure.ac | 18 ++ 19 files changed, 803 insertions(+), 7 deletions(-) create mode 100644 bolthur/server/usb/usbd/rpc/get/configuration.c create mode 100644 bolthur/server/usb/usbd/rpc/get/status.c diff --git a/bolthur/application/configure.ac b/bolthur/application/configure.ac index 1cf2017a..26c16f41 100644 --- a/bolthur/application/configure.ac +++ b/bolthur/application/configure.ac @@ -51,6 +51,24 @@ AC_ARG_WITH( [with_debug_debug_symbols=yes] ) +AC_ARG_WITH( + [ubsan], + AS_HELP_STRING( + [--with-ubsan], + [compile with ubsan enabled] + ), + [with_ubsan_enabled=yes] +) + +AC_ARG_WITH( + [asan], + AS_HELP_STRING( + [--with-asan], + [compile with asan enabled] + ), + [with_asan_enabled=yes] +) + # enable output and enable remote debugging together is not allowed AS_IF([test "x$enable_debug" == "xyes" && test "x$enable_release" == "xyes"], [ AC_MSG_ERROR([Enabled debug and release are not possible at the same time]) diff --git a/bolthur/kernel/configure.ac b/bolthur/kernel/configure.ac index b35db6aa..9580cee8 100644 --- a/bolthur/kernel/configure.ac +++ b/bolthur/kernel/configure.ac @@ -223,6 +223,24 @@ AC_ARG_WITH( [with_debug_debug_symbols=yes] ) +AC_ARG_WITH( + [ubsan], + AS_HELP_STRING( + [--with-ubsan], + [compile with ubsan enabled] + ), + [with_ubsan_enabled=yes] +) + +AC_ARG_WITH( + [asan], + AS_HELP_STRING( + [--with-asan], + [compile with asan enabled] + ), + [with_asan_enabled=yes] +) + # enable output and enable remote debugging together is not allowed AS_IF([test "x$enable_output" == "xyes" && test "x$enable_remote_debug" == "xyes"], [ AC_MSG_ERROR([Enabled kernel output and remote debug are not possible at the same time]) diff --git a/bolthur/library/configure.ac b/bolthur/library/configure.ac index db11b03b..08f38d81 100644 --- a/bolthur/library/configure.ac +++ b/bolthur/library/configure.ac @@ -51,6 +51,24 @@ AC_ARG_WITH( [with_debug_debug_symbols=yes] ) +AC_ARG_WITH( + [ubsan], + AS_HELP_STRING( + [--with-ubsan], + [compile with ubsan enabled] + ), + [with_ubsan_enabled=yes] +) + +AC_ARG_WITH( + [asan], + AS_HELP_STRING( + [--with-asan], + [compile with asan enabled] + ), + [with_asan_enabled=yes] +) + # enable output and enable remote debugging together is not allowed AS_IF([test "x$enable_debug" == "xyes" && test "x$enable_release" == "xyes"], [ AC_MSG_ERROR([Enabled debug and release are not possible at the same time]) diff --git a/bolthur/library/usb/usb.c b/bolthur/library/usb/usb.c index acd0084f..89010b0e 100644 --- a/bolthur/library/usb/usb.c +++ b/bolthur/library/usb/usb.c @@ -658,3 +658,167 @@ int usb_get_interface( // return success return 0; } + +/** + * @fn int usb_get_configuration(uint32_t, void**) + * @brief Method to get usb device configuration + * @param device_number + * @param target_buffer + * @return + */ +int usb_get_configuration( const uint32_t device_number, void** target_buffer ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "firing usb get descriptor\r\n" ) + #endif + // allocate shared memory + const size_t shm_id = _syscall_memory_shared_create( 0x1000 ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + return e; + } + // attach shared memory + const void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + return e; + } + // allocate request + usbd_get_configuration_t* control_request = malloc( sizeof( *control_request ) ); + if ( ! control_request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return error + return ENOMEM; + } + // clear out everything + memset( control_request, 0, sizeof( *control_request ) ); + // populate shm_id + control_request->shm_id = shm_id; + control_request->device_number = device_number; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_CONFIGURATION, + sizeof( *control_request ), + IOCTL_RDWR + ), + control_request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( control_request ); + // return eio + return EIO; + } + // allocate space for buffer + *target_buffer = malloc( control_request->configuration_length ); + if ( ! *target_buffer ) { + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to space for configuration\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( control_request ); + // return eio + return ENOMEM; + } + // clear space + memset( *target_buffer, 0, control_request->configuration_length ); + // copy over from shared memory + memcpy( *target_buffer, shm_addr, control_request->configuration_length ); + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free control message + free( control_request ); + // return result + return result; +} + +/** + * @fn int usb_get_status(uint32_t, libusb_device_status_t*) + * @brief Method to get usb device status + * @param device_number + * @param status + * @return + */ +int usb_get_status( const uint32_t device_number, libusb_device_status_t* status ) { + // validate parameter + if ( ! status ) { + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Invalid status parameter passed\r\n" ) + #endif + // return einval + return EINVAL; + } + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "firing usb get descriptor\r\n" ) + #endif + // allocate request + usbd_get_status_t* request = malloc( sizeof( *request ) ); + if ( ! request ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return error + return ENOMEM; + } + // clear out everything + memset( request, 0, sizeof( *request ) ); + // populate shm_id + request->device_number = device_number; + // perform request + const int result = ioctl( + fd_usbd, + IOCTL_BUILD_REQUEST( + USBD_GET_STATUS, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + // return eio + return EIO; + } + // set status + *status = request->status; + // free control message + free( request ); + // return result + return result; +} diff --git a/bolthur/library/usb/usb.h b/bolthur/library/usb/usb.h index d685bc9c..f15faa1f 100644 --- a/bolthur/library/usb/usb.h +++ b/bolthur/library/usb/usb.h @@ -33,5 +33,7 @@ int usb_register_handler( libusb_interface_class_t ); int usb_get_endpoint( uint32_t, uint32_t, uint32_t, libusb_endpoint_descriptor_t* ); int usb_get_interface( uint32_t, uint32_t, libusb_interface_descriptor_t* ); int usb_get_root_hub( uint32_t* ); +int usb_get_configuration( uint32_t, void** ); +int usb_get_status( uint32_t, libusb_device_status_t* ); #endif diff --git a/bolthur/server/configure.ac b/bolthur/server/configure.ac index 2621211a..cfb7e7f9 100644 --- a/bolthur/server/configure.ac +++ b/bolthur/server/configure.ac @@ -51,6 +51,24 @@ AC_ARG_WITH( [with_debug_debug_symbols=yes] ) +AC_ARG_WITH( + [ubsan], + AS_HELP_STRING( + [--with-ubsan], + [compile with ubsan enabled] + ), + [with_ubsan_enabled=yes] +) + +AC_ARG_WITH( + [asan], + AS_HELP_STRING( + [--with-asan], + [compile with asan enabled] + ), + [with_asan_enabled=yes] +) + # enable output and enable remote debugging together is not allowed AS_IF([test "x$enable_debug" == "xyes" && test "x$enable_release" == "xyes"], [ AC_MSG_ERROR([Enabled debug and release are not possible at the same time]) diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 41ee9039..5423f2ea 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -431,6 +431,59 @@ typedef struct __packed { uint8_t data[]; } libusb_hub_descriptor_t; +typedef enum { + LIBUSB_HID_COUNTRY_NOT_SUPPORTED = 0, + LIBUSB_HID_COUNTRY_ARABIC = 1, + LIBUSB_HID_COUNTRY_BELGIAN = 2, + LIBUSB_HID_COUNTRY_CANADIAN_BILINGUAL = 3, + LIBUSB_HID_COUNTRY_CANADIAN_FRENCH = 4, + LIBUSB_HID_COUNTRY_CZECH_REPUBLIC = 5, + LIBUSB_HID_COUNTRY_DANISH = 6, + LIBUSB_HID_COUNTRY_FINNISH = 7, + LIBUSB_HID_COUNTRY_FRENCH = 8, + LIBUSB_HID_COUNTRY_GERMAN = 9, + LIBUSB_HID_COUNTRY_GREEK = 10, + LIBUSB_HID_COUNTRY_HEBREW = 11, + LIBUSB_HID_COUNTRY_HUNGARY = 12, + LIBUSB_HID_COUNTRY_INTERNATIONAL = 13, + LIBUSB_HID_COUNTRY_ITALIAN = 14, + LIBUSB_HID_COUNTRY_JAPAN = 15, + LIBUSB_HID_COUNTRY_KOREAN = 16, + LIBUSB_HID_COUNTRY_LATIN_AMERICAN = 17, + LIBUSB_HID_COUNTRY_DUTCH = 18, + LIBUSB_HID_COUNTRY_NORWEGIAN = 19, + LIBUSB_HID_COUNTRY_PERSIAN = 20, + LIBUSB_HID_COUNTRY_POLAND = 21, + LIBUSB_HID_COUNTRY_PORTUGUESE = 22, + LIBUSB_HID_COUNTRY_RUSSIAN = 23, + LIBUSB_HID_COUNTRY_SLOVAKIAN = 24, + LIBUSB_HID_COUNTRY_SPANISH = 25, + LIBUSB_HID_COUNTRY_SWEDISH = 26, + LIBUSB_HID_COUNTRY_SWISS_FRENCH = 27, + LIBUSB_HID_COUNTRY_SWISS_GERMAN = 28, + LIBUSB_HID_COUNTRY_SWITZERLAND = 29, + LIBUSB_HID_COUNTRY_TAIWAN = 30, + LIBUSB_HID_COUNTRY_TURKISH_Q = 31, + LIBUSB_HID_COUNTRY_ENGLISH_UK = 32, + LIBUSB_HID_COUNTRY_ENGLISH_US = 33, + LIBUSB_HID_COUNTRY_YUGOSLAVIAN = 34, + LIBUSB_HID_COUNTRY_TURKISH_F = 35, +} libusb_hid_country_t; + +typedef struct __packed { + libusb_descriptor_type_t descriptor_type; + uint16_t length; +} libusb_hid_optional_descriptor_t; + +typedef struct __packed { + uint8_t descriptor_length; + libusb_descriptor_type_t descriptor_type : 8; + uint16_t hid_version; + libusb_hid_country_t hid_country : 8; + uint8_t descriptor_count; + libusb_hid_optional_descriptor_t optional[]; +} libusb_hid_descriptor_t; + typedef struct __packed { bool local_power : 1; bool over_current : 1; diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index e8aebda8..436b9ec6 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -55,6 +55,8 @@ #define USBD_CONTROL_MESSAGE USBD_GET_DESCRIPTION + 1 #define USBD_ATTACH_DEVICE USBD_CONTROL_MESSAGE + 1 #define USBD_GET_ROOTHUB USBD_ATTACH_DEVICE + 1 +#define USBD_GET_CONFIGURATION USBD_GET_ROOTHUB + 1 +#define USBD_GET_STATUS USBD_GET_CONFIGURATION + 1 // generic usb rpc structures typedef struct { @@ -148,4 +150,15 @@ typedef struct { uint8_t buffer[]; } usb_control_message_t; -#endif //LIBUSBD_H +typedef struct { + uint32_t device_number; + uint32_t configuration_length; + size_t shm_id; +} usbd_get_configuration_t; + +typedef struct { + uint32_t device_number; + libusb_device_status_t status; +} usbd_get_status_t; + +#endif diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c index 5e566d04..6f70682b 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -23,9 +23,55 @@ #include // local includes #include "../../rpc.h" +#include "../../global.h" #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" +/** + * @fn int hid_set_protocol(uint32_t, uint16_t, uint8_t) + * @brief Set hid protocol + * @param device_number + * @param interface + * @param protocol + * @return + */ +static int hid_set_protocol( + const uint32_t device_number, + const uint16_t interface, + const uint8_t protocol +) { + uint32_t last_transfer; + libusb_transfer_error_t error; + // perform control message + const int result = usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_OUT, + NULL, + 0, + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_SET_PROTOCOL, + .type = 0x21, + .index = interface, + .value = protocol, + .length = 0, + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); + // handle error + if ( 0 != result ) { + return result; + } + // handle error + if ( error != LIBUSB_TRANSFER_ERROR_NO_ERROR ) { + return EIO; + } + // return success + return 0; +} + /** * @fn void rpc_hid_attach(size_t, pid_t, size_t, size_t) * @brief Register rpc handler attach @@ -36,8 +82,183 @@ */ void rpc_hid_attach( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info -) { + ) { + // handle no data + if( ! data_info ) { + STARTUP_PRINT( "NO DATA PASSED!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + + // validate origin + if ( + origin != allowed_rpc_origin + && ! bolthur_rpc_validate_origin( origin, data_info ) + ) { + STARTUP_PRINT( "INVALID ORIGIN!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( + data_info, &data_size, true, NULL ); + if ( ! request ) { + STARTUP_PRINT( "ERROR WHILE FETCHING DATA: %s!\r\n", strerror( errno ) ) + _syscall_rpc_cleanup(); + return; + } + + // allocate space for pull_request + const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + + // get interface information + libusb_interface_descriptor_t interface_descriptor; + int result = usb_get_interface( + message->device_number, message->interface_number, &interface_descriptor ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get interface data\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // get endpoint information + libusb_endpoint_descriptor_t endpoint_descriptor; + result = usb_get_endpoint( + message->device_number, message->interface_number, 0, &endpoint_descriptor ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get endpoint information\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // validate class + if ( interface_descriptor.class != LIBUSB_INTERFACE_CLASS_HID ) { + STARTUP_PRINT( "Invalid interfacae class\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // validate interface endpoint + if ( interface_descriptor.endpoint_count < 1 ) { + STARTUP_PRINT( "Invalid hid device with fewer than one endpoint\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // validate endpoint + if ( + endpoint_descriptor.endpoint_address.direction != LIBUSB_DIRECTION_IN + || endpoint_descriptor.attributes.transfer != LIBUSB_TRANSFER_INTERRUPT + ) { + STARTUP_PRINT( "Invalid hid device with unusual endpoints\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // fetch device status + libusb_device_status_t status; + result = usb_get_status( message->device_number, &status ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get device status\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // ensure it's configured + if ( status != LIBUSB_DEVICE_STATUS_CONFIGURED ) { + STARTUP_PRINT( "Device not configured\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // check for boot device + if ( interface_descriptor.subclass == 1 ) { + if ( interface_descriptor.protocol == 1 ) { + STARTUP_PRINT( "Boot keyboard detected\r\n" ) + } else if ( interface_descriptor.protocol == 2 ) { + STARTUP_PRINT( "Boot mouse detected\r\n" ) + } else { + STARTUP_PRINT( "Unknown boot device detected\r\n" ) + } + + // switch protocol from boot to report mode + STARTUP_PRINT( "Reverting from boot to normal hid mode\r\n" ) + result = hid_set_protocol( + message->device_number, ( uint16_t )message->interface_number, 1 ); + if ( 0 != result ) { + STARTUP_PRINT( "Could not revert to report mode\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + } + + // fetch configuration + libusb_descriptor_header_t* header; + result = usb_get_configuration( message->device_number, ( void** )&header ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to fetch usb device configuration: %s\r\n", + strerror( result ) ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // find descriptor of hid + const libusb_hid_descriptor_t* descriptor = NULL; + uint32_t current_interface = message->interface_number + 1; + do { + // handle end reached + if ( ! header->descriptor_length ) { + break; + } + // switch descriptor type + switch ( header->descriptor_type ) { + case LIBUSB_DESCRIPTOR_INTERFACE: + current_interface = ( ( libusb_interface_descriptor_t* )header )->number; + break; + case LIBUSB_DESCRIPTOR_HID: + if ( current_interface == message->interface_number ) { + descriptor = ( libusb_hid_descriptor_t* )header; + } + break; + default: + break; + } + // some debug output + STARTUP_PRINT( "Descriptor %d with length %"PRIu8". Interface: %"PRIu32"\r\n", + header->descriptor_type, header->descriptor_length, current_interface ) + // handle descriptor found + if ( descriptor ) { + break; + } + // go to next header + header = ( libusb_descriptor_header_t* )( ( uint8_t* )header + header->descriptor_length ); + } while ( true ); + // validate hid descriptor + if ( ! descriptor ) { + STARTUP_PRINT( "No hid descriptor in %s with interface %"PRIu32". Cannot be a hid device\r\n", + usb_get_description(message->device_number), message->interface_number + 1 ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // check for hid version + if ( descriptor->hid_version > 0x111 ) { + STARTUP_PRINT( "Unsupported hid version: %"PRIx16".%"PRIx16"\r\n", + descriptor->hid_version >> 8, descriptor->hid_version & 0xff ) + _syscall_rpc_cleanup(); + free( request ); + return; + } + // some debug output + STARTUP_PRINT( "Detected hid device: %"PRIx16".%"PRIx16"\r\n", + descriptor->hid_version >> 8, descriptor->hid_version & 0xff ) } diff --git a/bolthur/server/usb/usbd/Makefile.am b/bolthur/server/usb/usbd/Makefile.am index 4e2ca14f..951e0218 100644 --- a/bolthur/server/usb/usbd/Makefile.am +++ b/bolthur/server/usb/usbd/Makefile.am @@ -5,11 +5,13 @@ bin_PROGRAMS = usbd usbd_SOURCES = \ rpc/attach/device.c \ rpc/control/message.c \ + rpc/get/configuration.c \ rpc/get/description.c \ rpc/get/descriptor.c \ rpc/get/endpoint.c \ rpc/get/interface.c \ rpc/get/roothub.c \ + rpc/get/status.c \ rpc/handler/register.c \ rpc/handler/unregister.c \ rpc/init.c \ diff --git a/bolthur/server/usb/usbd/call.c b/bolthur/server/usb/usbd/call.c index 9f7b1be3..da29780e 100644 --- a/bolthur/server/usb/usbd/call.c +++ b/bolthur/server/usb/usbd/call.c @@ -59,7 +59,7 @@ int call_attach( libusb_device_t* dev, const uint32_t interface_number ) { dev->device_child_reset_handler = handler; dev->device_check_connection_handler = handler; /// FIXME: GENERATE CORRECT REQUEST - const size_t request_size = sizeof( vfs_ioctl_perform_request_t ) + constexpr size_t request_size = sizeof( vfs_ioctl_perform_request_t ) + sizeof( usb_generic_attach_t ); vfs_ioctl_perform_request_t* request = malloc( request_size ); if ( ! request ) { diff --git a/bolthur/server/usb/usbd/main.c b/bolthur/server/usb/usbd/main.c index cee943a9..b805db5a 100644 --- a/bolthur/server/usb/usbd/main.c +++ b/bolthur/server/usb/usbd/main.c @@ -65,8 +65,10 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { USBD_CONTROL_MESSAGE, USBD_GET_ROOTHUB, USBD_ATTACH_DEVICE, + USBD_GET_CONFIGURATION, + USBD_GET_STATUS, }; - if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 9 ) ) { + if ( !dev_add_file( USBD_DEVICE_PATH, device_info, 11 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/usbd/rpc.h b/bolthur/server/usb/usbd/rpc.h index 80dd23e1..ed9c5d99 100644 --- a/bolthur/server/usb/usbd/rpc.h +++ b/bolthur/server/usb/usbd/rpc.h @@ -26,11 +26,13 @@ bool rpc_init( void ); void rpc_attach_device( size_t, pid_t, size_t, size_t ); void rpc_control_message( size_t, pid_t, size_t, size_t ); +void rpc_get_configuration( size_t, pid_t, size_t, size_t ); void rpc_get_description( size_t, pid_t, size_t, size_t ); void rpc_get_descriptor( size_t, pid_t, size_t, size_t ); void rpc_get_endpoint( size_t, pid_t, size_t, size_t ); void rpc_get_interface( size_t, pid_t, size_t, size_t ); void rpc_get_roothub( size_t, pid_t, size_t, size_t ); +void rpc_get_status( size_t, pid_t, size_t, size_t ); void rpc_handler_register( size_t, pid_t, size_t, size_t ); void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/usb/usbd/rpc/get/configuration.c b/bolthur/server/usb/usbd/rpc/get/configuration.c new file mode 100644 index 00000000..341760db --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/configuration.c @@ -0,0 +1,127 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusbd.h" + +/** + * @fn void rpc_get_description(size_t, pid_t, size_t, size_t) + * @brief Get usb device description + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_configuration( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate space for pull_request + usbd_get_configuration_t* control_message = + ( usbd_get_configuration_t* )request->container; + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( + control_message->shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + // set error + error.status = -errno; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // find device + libusb_device_t* device = head; + while ( device ) { + if ( device->number == control_message->device_number ) { + break; + } + device = device->next; + } + // handle not found + if ( ! device ) { + error.status = -ENODATA; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // free request + free( request ); + free( response ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // copy over full configuration + memcpy( shm_addr, device->full_configuration, device->configuration.total_length ); + // populate return fields + control_message->configuration_length = device->configuration.total_length; + // detach shared memory + _syscall_memory_shared_detach( control_message->shm_id ); + // populate status and just copy over data from request + response->status = 0; + memcpy( response->container, request->container, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/get/status.c b/bolthur/server/usb/usbd/rpc/get/status.c new file mode 100644 index 00000000..4d814efd --- /dev/null +++ b/bolthur/server/usb/usbd/rpc/get/status.c @@ -0,0 +1,104 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../rpc.h" +// driver includes +#include "../../usbd.h" +#include "../../../../libusbd.h" + +/** + * @fn void rpc_get_status(size_t, pid_t, size_t, size_t) + * @brief Get usb device description + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_status( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + error.status = -EIO; + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + const size_t container_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // get status request + usbd_get_status_t* status = ( usbd_get_status_t* )request->container; + // find device + const libusb_device_t* dev = head; + while ( dev ) { + if ( dev->number == status->device_number ) { + break; + } + dev = dev->next; + } + // handle no device + if ( ! dev ) { + error.status = -EIO; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate status + status->status = dev->status; + // allocate response structure + const size_t response_size = sizeof( vfs_ioctl_perform_response_t ) + container_size; + vfs_ioctl_perform_response_t* response = malloc( response_size ); + if ( ! response ) { + error.status = -ENOMEM; + // free request + free( request ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // clear out + memset( response, 0, response_size ); + // copy over description + response->status = 0; + memcpy( response->container, status, container_size ); + // return from rpc + bolthur_rpc_return( RPC_VFS_IOCTL, response, response_size, NULL, 0 ); + // free up memory + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/usbd/rpc/init.c b/bolthur/server/usb/usbd/rpc/init.c index d9e7db81..7e48763a 100644 --- a/bolthur/server/usb/usbd/rpc/init.c +++ b/bolthur/server/usb/usbd/rpc/init.c @@ -83,5 +83,17 @@ bool rpc_init( void ) { STARTUP_PRINT( "Unable to register unregister device handler!\r\n" ) return false; } + // register handler get configuration + bolthur_rpc_bind( USBD_GET_CONFIGURATION, rpc_get_configuration, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get configuration handler!\r\n" ) + return false; + } + // register handler get status + bolthur_rpc_bind( USBD_GET_STATUS, rpc_get_status, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get status handler!\r\n" ) + return false; + } return true; } diff --git a/build-aux/m4/flag.m4 b/build-aux/m4/flag.m4 index 729ce3cf..245b7df8 100644 --- a/build-aux/m4/flag.m4 +++ b/build-aux/m4/flag.m4 @@ -115,7 +115,11 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_FLAG], [ AS_IF([test "x$with_debug_symbols" == "xyes"], [ # debug symbols and sanitizer AX_APPEND_COMPILE_FLAGS([-g -Og]) + ]) + AS_IF([test "x$with_ubsan_enabled" == "xyes"], [ AX_APPEND_COMPILE_FLAGS([-fsanitize=undefined]) + ]) + AS_IF([test "x$with_asan_enabled" == "xyes"], [ AX_APPEND_COMPILE_FLAGS([-fsanitize=kernel-address]) ]) # optimization level diff --git a/build-aux/m4/host.m4 b/build-aux/m4/host.m4 index cd9ea708..62a83be2 100644 --- a/build-aux/m4/host.m4 +++ b/build-aux/m4/host.m4 @@ -121,7 +121,7 @@ AC_DEFUN([BOLTHUR_KERNEL_SET_HOST], [ AC_DEFINE([PRINT_SSP],[1]) ]) - AS_IF([test "x$with_debug_symbols" == "xyes"], [ + AS_IF([test "x$with_asan_enabled" == "xyes"], [ AC_DEFINE([HAS_SANITIZER],[1]) ]) diff --git a/configure.ac b/configure.ac index ecd8d921..17b60cb1 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,24 @@ AC_ARG_WITH( [with_debug_debug_symbols=yes] ) +AC_ARG_WITH( + [ubsan], + AS_HELP_STRING( + [--with-ubsan], + [compile with ubsan enabled] + ), + [with_ubsan_enabled=yes] +) + +AC_ARG_WITH( + [asan], + AS_HELP_STRING( + [--with-asan], + [compile with asan enabled] + ), + [with_asan_enabled=yes] +) + # enable output and enable remote debugging together is not allowed AS_IF([test "x$enable_output" == "xyes" && test "x$enable_remote_debug" == "xyes"], [ AC_MSG_ERROR([Enabled kernel output and remote debug are not possible at the same time]) From 38ae9cb415e3afde5a648d8a28b19a4db0aaecf2 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 14:33:08 +0200 Subject: [PATCH 027/144] - Added hid enums and structures to usbd - Replaced libhid_interface_type_t by libusb_hid_usage_page_desktop_t - Continued working on hid attach - Added handler_call_attach helper to hid handler logic - Replaced RPC_CUSTOM_START within usbd call.c by GENERIC_ATTACH - Fixed tree usage in hid handler logic - Started adding logic to keyboard attach - Started adding logic to mouse attach - Added store of hub device to attach into a hub list --- bolthur/library/hid/hid.c | 4 +- bolthur/library/hid/hid.h | 2 +- bolthur/server/libusb.h | 242 ++++++- bolthur/server/libusbd.h | 4 +- bolthur/server/usb/device/hid/hid/Makefile.am | 1 + bolthur/server/usb/device/hid/hid/handler.c | 111 ++- bolthur/server/usb/device/hid/hid/handler.h | 7 +- bolthur/server/usb/device/hid/hid/hid.c | 47 ++ bolthur/server/usb/device/hid/hid/hid.h | 27 + .../usb/device/hid/hid/rpc/hid/attach.c | 652 +++++++++++++++++- bolthur/server/usb/device/hid/keyboard/main.c | 2 +- .../device/hid/keyboard/rpc/keyboard/attach.c | 35 +- bolthur/server/usb/device/hid/mouse/main.c | 2 +- .../usb/device/hid/mouse/rpc/mouse/attach.c | 37 +- bolthur/server/usb/device/hub/Makefile.am | 1 + bolthur/server/usb/device/hub/hub.c | 48 ++ bolthur/server/usb/device/hub/hub.h | 4 + .../server/usb/device/hub/rpc/hub/attach.c | 4 +- bolthur/server/usb/usbd/call.c | 4 +- 19 files changed, 1186 insertions(+), 48 deletions(-) create mode 100644 bolthur/server/usb/device/hid/hid/hid.c create mode 100644 bolthur/server/usb/device/hid/hid/hid.h create mode 100644 bolthur/server/usb/device/hub/hub.c diff --git a/bolthur/library/hid/hid.c b/bolthur/library/hid/hid.c index a012885d..ec03f606 100644 --- a/bolthur/library/hid/hid.c +++ b/bolthur/library/hid/hid.c @@ -54,12 +54,12 @@ int hid_init( void ) { } /** - * @fn int hid_register_handler(libhid_interface_type_t) + * @fn int hid_register_handler(libusb_hid_usage_page_desktop_t) * @brief Method to attach a new discovered device * @param type * @return */ -int hid_register_handler( const libhid_interface_type_t type ) { +int hid_register_handler( const libusb_hid_usage_page_desktop_t type ) { const pid_t pid = getpid(); // debug message #if defined( LIBHID_ENABLE_DEBUG ) diff --git a/bolthur/library/hid/hid.h b/bolthur/library/hid/hid.h index aa01b11d..6464867e 100644 --- a/bolthur/library/hid/hid.h +++ b/bolthur/library/hid/hid.h @@ -23,6 +23,6 @@ #include "../../server/libusb.h" int hid_init( void ); -int hid_register_handler( libhid_interface_type_t ); +int hid_register_handler( libusb_hid_usage_page_desktop_t ); #endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index 5423f2ea..eb5ce071 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -350,11 +350,6 @@ typedef enum { LIBUSB_TRANSFER_ERROR_PROCESSING = 1 << 10, } libusb_transfer_error_t; -typedef enum { - LIBHID_INTERFACE_TYPE_MOUSE = 2, - LIBHID_INTERFACE_TYPE_KEYBOARD = 6, -} libhid_interface_type_t; - typedef struct { uint32_t device_driver; uint32_t data_size; @@ -553,13 +548,16 @@ typedef enum { DEVICE_DRIVER_MOUSE = 0x4b424431, } device_driver_t; -typedef struct { +typedef struct libusb_hub_device libusb_hub_device_t; +typedef struct libusb_hub_device { libusb_driver_data_header header; libusb_hub_full_status_t status; libusb_hub_descriptor_t* descriptor; uint32_t max_children; libusb_hub_port_full_status_t port_status[ 255 ]; uint32_t children[ 255 ]; + libusb_hub_device_t* next; + libusb_hub_device_t* prev; } libusb_hub_device_t; typedef enum { @@ -567,6 +565,238 @@ typedef enum { LIBUSB_HUB_FEATURE_OVER_CURRENT = 1, } libusb_hub_feature_t; +typedef enum { + LIBUSB_HID_REPORT_TAG_MAIN_INPUT = 0x20, + LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT = 0x24, + LIBUSB_HID_REPORT_TAG_MAIN_FEATURE = 0x2c, + LIBUSB_HID_REPORT_TAG_MAIN_COLLECTION = 0x28, + LIBUSB_HID_REPORT_TAG_MAIN_END_COLLECTION = 0x30, + LIBUSB_HID_REPORT_TAG_GLOBAL_USAGE_PAGE = 0x1, + LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MINIMUM = 0x5, + LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MAXIMUM = 0x9, + LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MINIMUM = 0xd, + LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MAXIMUM = 0x11, + LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT_EXPONENT = 0x15, + LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT = 0x19, + LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_SIZE = 0x1d, + LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID = 0x21, + LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT = 0x25, + LIBUSB_HID_REPORT_TAG_GLOBAL_PUSH = 0x29, + LIBUSB_HID_REPORT_TAG_GLOBAL_POP = 0x2d, + LIBUSB_HID_REPORT_TAG_LOCAL_USAGE = 0x2, + LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MINIMUM = 0x6, + LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MAXIMUM = 0xa, + LIBUSB_HID_REPORT_TAG_LOCAL_DESIGNATOR_INDEX = 0xe, + LIBUSB_HID_REPORT_TAG_LOCAL_DESIGNATOR_MINIMUM = 0x12, + LIBUSB_HID_REPORT_TAG_LOCAL_DESIGNATOR_MAXIMUM = 0x16, + LIBUSB_HID_REPORT_TAG_LOCAL_STRING_INDEX = 0x1e, + LIBUSB_HID_REPORT_TAG_LOCAL_STRING_MINIMUM = 0x22, + LIBUSB_HID_REPORT_TAG_LOCAL_STRING_MAXIMUM = 0x26, + LIBUSB_HID_REPORT_TAG_LOCAL_DELIMITER = 0x2a, + LIBUSB_HID_REPORT_TAG_LONG = 0x3f, +} libusb_hid_report_tag_t; + +typedef struct __packed { + uint8_t size : 2; + libusb_hid_report_tag_t tag : 6; +} libusb_hid_report_item_t; + +typedef struct __packed { + bool constant : 1; + bool variable : 1; + bool relative : 1; + bool wrap : 1; + bool non_linear : 1; + bool no_preferred : 1; + bool hull : 1; + bool _volatile : 1; + bool buffered_bytes : 1; + uint32_t reserved : 23; +} libusb_hid_main_item_t; + +typedef enum { + LIBUSB_HID_MAIN_COLLECTION_PHYSICAL = 0, + LIBUSB_HID_MAIN_COLLECTION_APPLICATION = 1, + LIBUSB_HID_MAIN_COLLECTION_LOGICAL = 2, + LIBUSB_HID_MAIN_COLLECTION_REPORT = 3, + LIBUSB_HID_MAIN_COLLECTION_NAMED_ARRAY = 4, + LIBUSB_HID_MAIN_COLLECTION_USAGE_SWITCH = 5, + LIBUSB_HID_MAIN_COLLECTION_USAGE_MODIFIER = 6, +} libusb_hid_main_collection_t; + +typedef enum { + LIBUSB_HID_USAGE_PAGE_UNDEFINED = 0, + LIBUSB_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROL = 1, + LIBUSB_HID_USAGE_PAGE_SIMULATION_CONTROL = 2, + LIBUSB_HID_USAGE_PAGE_VR_CONTROL = 3, + LIBUSB_HID_USAGE_PAGE_SPORT_CONTROL = 4, + LIBUSB_HID_USAGE_PAGE_GAME_CONTROL = 5, + LIBUSB_HID_USAGE_PAGE_GENERIC_DEVICE_CONTROL = 6, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_CONTROL = 7, + LIBUSB_HID_USAGE_PAGE_LED = 8, + LIBUSB_HID_USAGE_PAGE_BUTTON = 9, + LIBUSB_HID_USAGE_PAGE_ORDINAL = 10, + LIBUSB_HID_USAGE_PAGE_TELEPHONY = 11, + LIBUSB_HID_USAGE_PAGE_CONSUMER = 12, + LIBUSB_HID_USAGE_PAGE_DIGITIZER = 13, + LIBUSB_HID_USAGE_PAGE_PID_PAGE = 15, + LIBUSB_HID_USAGE_PAGE_UNICODE = 16, + LIBUSB_HID_USAGE_PAGE_USAGE_PAGE = 0xffff, +} libusb_hid_usage_page_t; + +typedef enum { + LIBUSB_HID_USAGE_PAGE_DESKTOP_POINT = 0, + LIBUSB_HID_USAGE_PAGE_DESKTOP_MOUSE = 1, + LIBUSB_HID_USAGE_PAGE_DESKTOP_JOYSTICK = 4, + LIBUSB_HID_USAGE_PAGE_DESKTOP_GAMEPAD = 5, + LIBUSB_HID_USAGE_PAGE_DESKTOP_KEYBOARD = 6, + LIBUSB_HID_USAGE_PAGE_DESKTOP_KEYPAD = 7, + LIBUSB_HID_USAGE_PAGE_DESKTOP_MULTI_AXIS_CONTROLLER = 8, + LIBUSB_HID_USAGE_PAGE_DESKTOP_TABLE_PC_CONTROL = 9, + LIBUSB_HID_USAGE_PAGE_DESKTOP_X = 0x30, + LIBUSB_HID_USAGE_PAGE_DESKTOP_Y = 0x31, + LIBUSB_HID_USAGE_PAGE_DESKTOP_Z = 0x32, + LIBUSB_HID_USAGE_PAGE_DESKTOP_RX = 0x33, + LIBUSB_HID_USAGE_PAGE_DESKTOP_RY = 0x34, + LIBUSB_HID_USAGE_PAGE_DESKTOP_RZ = 0x35, + LIBUSB_HID_USAGE_PAGE_DESKTOP_SLIDER = 0x36, + LIBUSB_HID_USAGE_PAGE_DESKTOP_DIAL = 0x37, + LIBUSB_HID_USAGE_PAGE_DESKTOP_WHEEL = 0x38, + LIBUSB_HID_USAGE_PAGE_DESKTOP_HAT_SWITCH = 0x39, + LIBUSB_HID_USAGE_PAGE_DESKTOP_COUNTED_BUFFER = 0x3a, + LIBUSB_HID_USAGE_PAGE_DESKTOP_BYTE_COUNT = 0x3b, + LIBUSB_HID_USAGE_PAGE_DESKTOP_MOTION_WAKE_UP = 0x3c, + LIBUSB_HID_USAGE_PAGE_DESKTOP_START = 0x3d, + LIBUSB_HID_USAGE_PAGE_DESKTOP_SELECT = 0x3e, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VX = 0x40, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VY = 0x41, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VZ = 0x42, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VBR_X = 0x43, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VBR_Y = 0x44, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VBR_Z = 0x45, + LIBUSB_HID_USAGE_PAGE_DESKTOP_VNO = 0x46, + LIBUSB_HID_USAGE_PAGE_DESKTOP_FEATURE_NOTIFICATION = 0x47, + LIBUSB_HID_USAGE_PAGE_DESKTOP_RESOLUTION_MULTIPLIER = 0x48, + LIBUSB_HID_USAGE_PAGE_DESKTOP_DUMMY = 0xffff, +} libusb_hid_usage_page_desktop_t; + +typedef enum { + LIBUSB_HID_USAGE_PAGE_KEYBOARD_ERROR_ROLL_OVER = 1, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_POST_FAIL = 2, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_ERROR_UNDEFINED = 3, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_CONTROL = 0xe0, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_SHIFT = 0xe1, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_ALT = 0xe2, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_GUI = 0xe3, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_RIGHT_CONTROL = 0xe4, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_RIGHT_SHIFT = 0xe5, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_RIGHT_ALT = 0xe6, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_RIGHT_GUI = 0xe7, + LIBUSB_HID_USAGE_PAGE_KEYBOARD_DUMMY = 0xffff, +} libusb_hid_usage_page_keyboard_t; + +typedef enum { + LIBUSB_HID_USAGE_PAGE_LED_NUMBER_LOCK = 1, + LIBUSB_HID_USAGE_PAGE_LED_CAPSLOCK = 2, + LIBUSB_HID_USAGE_PAGE_LED_SCROLL_LOCK = 3, + LIBUSB_HID_USAGE_PAGE_LED_COMPOSE = 4, + LIBUSB_HID_USAGE_PAGE_LED_KANA = 5, + LIBUSB_HID_USAGE_PAGE_LED_POWER = 6, + LIBUSB_HID_USAGE_PAGE_LED_SHIFT = 7, + LIBUSB_HID_USAGE_PAGE_LED_MUTE = 9, + LIBUSB_HID_USAGE_PAGE_LED_DUMMY = 0xffff, +} libusb_hid_usage_page_led_t; + +typedef enum { + LIBUSB_HID_REPORT_TYPE_INPUT = 1, + LIBUSB_HID_REPORT_TYPE_OUTPUT = 2, + LIBUSB_HID_REPORT_TYPE_FEATURE = 3, +} libusb_hid_report_type_t; + +typedef struct __packed { + union { + libusb_hid_usage_page_desktop_t desktop : 16; + libusb_hid_usage_page_keyboard_t keyboard : 16; + libusb_hid_usage_page_led_t led : 16; + }; + libusb_hid_usage_page_t page : 16; +} libusb_hid_full_usage_t; + +typedef enum { + LIBUSB_HID_UNIT_SYSTEM_NONE = 0, + LIBUSB_HID_UNIT_SYSTEM_STANDARD_LINEAR = 1, + LIBUSB_HID_UNIT_SYSTEM_STANDARD_ROTATION = 2, + LIBUSB_HID_UNIT_SYSTEM_ENGLISH_LINEAR = 3, + LIBUSB_HID_UNIT_SYSTEM_ENGLISH_ROTATION = 4, +} libusb_hid_unit_system_t; + +typedef struct __packed { + libusb_hid_unit_system_t system : 4; + int8_t length : 4; + int8_t mass : 4; + int8_t time : 4; + int8_t temperature : 4; + int8_t current : 4; + int8_t luminous_intensity : 4; + uint8_t reserved : 4; +} libusb_hid_unit_t; + +typedef struct { + uint8_t size; + uint8_t offset; + uint8_t count; + libusb_hid_main_item_t attribute __aligned(4); + libusb_hid_full_usage_t usage; + libusb_hid_full_usage_t physical_usage; + int32_t logical_minimum; + int32_t logical_maximum; + int32_t physical_minimum; + int32_t physical_maximum; + libusb_hid_unit_t unit; + int32_t unit_exponent; + union { + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + bool _bool; + void* ptr; + } value; +} libusb_hid_parser_fields_t; + +typedef struct { + uint8_t index; + uint8_t field_count; + uint8_t id; + libusb_hid_report_type_t type; + uint8_t report_length; + uint8_t* report_buffer; + libusb_hid_parser_fields_t fields[] __aligned(4); +} libusb_hid_parser_report_t; + +typedef struct { + libusb_hid_full_usage_t application; + uint8_t report_count; + uint8_t interface; + libusb_hid_parser_report_t* report[] __aligned(4); +} libusb_hid_parser_result_t; + +typedef struct libusb_hid_device libusb_hid_device_t; +typedef struct libusb_hid_device { + libusb_driver_data_header header; + libusb_hid_descriptor_t* descriptor; + libusb_hid_parser_result_t* parser_result; + libusb_driver_data_header* driver_data; + + pid_t device_detached_handler; + pid_t device_deallocate_handler; + + libusb_hid_device_t* next; + libusb_hid_device_t* prev; +} libusb_hid_device_t; + // enable warnings again #pragma GCC diagnostic pop diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index 436b9ec6..1da39f47 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -67,12 +67,12 @@ typedef struct { // hid rpc structures typedef struct { - libhid_interface_type_t type; + libusb_hid_usage_page_desktop_t type; pid_t handler; } hid_register_device_handler_t; typedef struct { - libhid_interface_type_t type; + libusb_hid_usage_page_desktop_t type; pid_t handler; } hid_unregister_device_handler_t; diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index c13b51bd..6e5f4081 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -16,5 +16,6 @@ hid_SOURCES = \ rpc/hid/detach.c \ rpc/init.c \ handler.c \ + hid.c \ main.c hid_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/hid/handler.c b/bolthur/server/usb/device/hid/hid/handler.c index fb9e609e..66800cf7 100644 --- a/bolthur/server/usb/device/hid/hid/handler.c +++ b/bolthur/server/usb/device/hid/hid/handler.c @@ -20,7 +20,9 @@ #include #include #include +#include #include "handler.h" +#include "../../../../libusbd.h" #include "../../../../../library/collection/avl/avl.h" static avl_tree_t* management_tree; @@ -38,14 +40,14 @@ static int32_t compare_container( const avl_node_t* node_a, const avl_node_t* node_b ) { - const pid_container_t* container_a = PID_HANDLER_GET_ENTRY( node_a ); - const pid_container_t* container_b = PID_HANDLER_GET_ENTRY( node_b ); + const libusb_hid_usage_page_desktop_t value_a = (libusb_hid_usage_page_desktop_t)node_a->data; + const libusb_hid_usage_page_desktop_t value_b = (libusb_hid_usage_page_desktop_t)node_b->data; // return 0 if equal - if ( container_a->handler == container_b->handler ) { + if ( value_a == value_b ) { return 0; } // return -1 or 1 depending on what is greater - return container_a->handler > container_b->handler ? -1 : 1; + return value_a > value_b ? -1 : 1; } /** @@ -60,14 +62,14 @@ static int32_t lookup_container( const avl_node_t* node, const void* value ) { - pid_t handler = ( pid_t )value; - pid_container_t* container = PID_HANDLER_GET_ENTRY( node ); + const libusb_hid_usage_page_desktop_t type = ( libusb_hid_usage_page_desktop_t )value; + const libusb_hid_usage_page_desktop_t node_type = ( libusb_hid_usage_page_desktop_t )node->data; // return 0 if equal - if ( container->handler == handler ) { + if ( node_type == type ) { return 0; } // return -1 or 1 depending on what is greater - return container->handler > handler ? -1 : 1; + return node_type > type ? -1 : 1; } /** @@ -103,19 +105,19 @@ int handler_init( void ) { } /** - * @fn int handler_register(libhid_interface_type_t, pid_t) + * @fn int handler_register(libusb_hid_usage_page_desktop_t, pid_t) * @brief Method to register a handler * @param type * @param handler * @return */ -int handler_register( const libhid_interface_type_t type, const pid_t handler ) { +int handler_register( const libusb_hid_usage_page_desktop_t type, const pid_t handler ) { // validate if ( ! management_tree ) { return EINVAL; } // try to find possible handler - const avl_node_t* found = avl_find_by_data( management_tree, ( void* )handler ); + const avl_node_t* found = avl_find_by_data( management_tree, ( void* )type ); // handle found if ( found ) { return EINVAL; @@ -141,13 +143,13 @@ int handler_register( const libhid_interface_type_t type, const pid_t handler ) } /** - * @fn int handler_unregister(libhid_interface_type_t, pid_t) + * @fn int handler_unregister(libusb_hid_usage_page_desktop_t, pid_t) * @brief Unregister a handler * @param type * @param handler * @return */ -int handler_unregister( const libhid_interface_type_t type, const pid_t handler ) { +int handler_unregister( const libusb_hid_usage_page_desktop_t type, const pid_t handler ) { // validate if ( ! management_tree ) { return EINVAL; @@ -160,7 +162,7 @@ int handler_unregister( const libhid_interface_type_t type, const pid_t handler } // compare handlers pid_container_t* item = PID_HANDLER_GET_ENTRY( found ); - // handle no matcj + // handle no match if ( item->handler != handler ) { return EINVAL; } @@ -173,13 +175,13 @@ int handler_unregister( const libhid_interface_type_t type, const pid_t handler } /** - * @fn int handler_get(libhid_interface_type_t, pid_t*) + * @fn int handler_get(libusb_hid_usage_page_desktop_t, pid_t*) * @brief Get a handler * @param type * @param handler * @return */ -int handler_get( const libhid_interface_type_t type, pid_t* handler ) { +int handler_get( const libusb_hid_usage_page_desktop_t type, pid_t* handler ) { // validate if ( ! handler || ! management_tree ) { return EINVAL; @@ -188,12 +190,85 @@ int handler_get( const libhid_interface_type_t type, pid_t* handler ) { const avl_node_t* found = avl_find_by_data( management_tree, ( void* )type ); // handle not found if ( ! found ) { - *handler = 0; + *handler = -1; // handle found } else { - pid_container_t* container = PID_HANDLER_GET_ENTRY( found ); + const pid_container_t* container = PID_HANDLER_GET_ENTRY( found ); *handler = container->handler; } // return success return 0; } + +/** + * @fn int handler_call_attach(libusb_hid_usage_page_desktop_t, libusb_hid_device_t*, uint32_t, uint32_t) + * @brief Wrapper to call attach + * @param type + * @param device + * @param device_number + * @param interface_number + * @return + */ +int handler_call_attach( + const libusb_hid_usage_page_desktop_t type, + libusb_hid_device_t* device, + const uint32_t device_number, + const uint32_t interface_number +) { + // get handler + pid_t handler; + const int result = handler_get( type, &handler ); + // handle error + if ( result != 0 ) { + return result; + } + // handle success but no handler bound => return success + if ( -1 == handler ) { + STARTUP_PRINT( "No handler found for type %d\r\n", type ); + return 0; + } + // set handler pids for device + device->device_deallocate_handler = handler; + device->device_detached_handler = handler; + // generate request + const size_t request_size = sizeof( vfs_ioctl_perform_request_t ) + sizeof( usb_generic_attach_t ); + vfs_ioctl_perform_request_t* request = malloc( request_size ); + if ( ! request ) { + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, request_size ); + // populate container + ( ( usb_generic_attach_t* )request->container )->device_number = device_number; + ( ( usb_generic_attach_t* )request->container)->interface_number = interface_number; + // attach is defined as first custom message + bolthur_rpc_raise_generic( + GENERIC_ATTACH, + handler, + request, + request_size, + NULL, + GENERIC_ATTACH, + request, + request_size, + 0, + 0, + NULL, + true, + false + ); + // handle error + if ( errno ) { + // cache errno + const int e = errno; + // free request + free( request ); + // return error + return e; + } + // free request + free( request ); + // return success + return 0; +} diff --git a/bolthur/server/usb/device/hid/hid/handler.h b/bolthur/server/usb/device/hid/hid/handler.h index 989013f6..cdbc1e29 100644 --- a/bolthur/server/usb/device/hid/hid/handler.h +++ b/bolthur/server/usb/device/hid/hid/handler.h @@ -32,8 +32,9 @@ typedef struct { ( pid_container_t* )( ( uint8_t* )n - offsetof( pid_container_t, node ) ) int handler_init( void ); -int handler_register( libhid_interface_type_t, pid_t ); -int handler_unregister( libhid_interface_type_t, pid_t ); -int handler_get( libhid_interface_type_t, pid_t* ); +int handler_register( libusb_hid_usage_page_desktop_t, pid_t ); +int handler_unregister( libusb_hid_usage_page_desktop_t, pid_t ); +int handler_get( libusb_hid_usage_page_desktop_t, pid_t* ); +int handler_call_attach( libusb_hid_usage_page_desktop_t, libusb_hid_device_t*, uint32_t, uint32_t ); #endif diff --git a/bolthur/server/usb/device/hid/hid/hid.c b/bolthur/server/usb/device/hid/hid/hid.c new file mode 100644 index 00000000..1d48a64a --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/hid.c @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "hid.h" + +libusb_hid_device_t* hid_head = NULL; + +/** + * @fn void hid_append(libusb_hid_device_t*) + * @brief Append hid to handled devices + * @param hid + */ +void hid_append( libusb_hid_device_t* hid ) { + // loop to last one + libusb_hid_device_t* current = hid_head; + libusb_hid_device_t* found = NULL; + while ( current ) { + found = current; + current = current->next; + } + // handle empty + if ( ! found ) { + hid_head = hid; + hid->prev = NULL; + hid->next = NULL; + return; + } + // attach to list + found->next = hid; + hid->prev = found; +} diff --git a/bolthur/server/usb/device/hid/hid/hid.h b/bolthur/server/usb/device/hid/hid/hid.h new file mode 100644 index 00000000..d0b4a3d7 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/hid.h @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _HID_H +#define _HID_H + +#include "../../../../libusb.h" + +void hid_append( libusb_hid_device_t* ); + +#endif diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c index 6f70682b..bab07ba7 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -22,11 +22,72 @@ #include #include // local includes +#include "hid.h" +#include "../../handler.h" #include "../../rpc.h" #include "../../global.h" #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" +typedef struct { + uint8_t count; + uint8_t indent; + bool input; + bool output; + bool feature; +} hid_report_action_count_t; + +typedef struct { + uint8_t report_id; + uint8_t field_count; + libusb_hid_report_type_t report_type; +} hid_report_field_data_t; + +typedef struct { + uint32_t count; + uint8_t current; + uint8_t report; + hid_report_field_data_t data[]; +} hid_report_field_t; + +typedef struct { + libusb_hid_parser_result_t* result; + uint32_t count; + uint32_t size; + libusb_hid_full_usage_t* usage; + libusb_hid_full_usage_t physical; + int32_t logical_minimum; + int32_t logical_maximum; + int32_t physical_minimum; + int32_t physical_maximum; + libusb_hid_unit_t unit; + int32_t unit_exponent; + libusb_hid_usage_page_t page; + uint8_t report; +} hid_field_t; + +typedef void( *hid_report_action_t )( void* data, libusb_hid_report_tag_t tag, uint32_t value ); + +/** + * @fn void hid_destroy_device(libusb_hid_device_t*) + * @brief Helper to destroy hid device + * @param device + */ +static void hid_destroy_device( libusb_hid_device_t* device ) { + if ( ! device ) { + return; + } + if ( device->parser_result ) { + for ( size_t idx = 0; idx < device->parser_result->report_count; idx++ ) { + if ( device->parser_result->report[ idx ] ) { + free( device->parser_result->report[ idx ] ); + } + } + free( device->parser_result ); + } + free( device ); +} + /** * @fn int hid_set_protocol(uint32_t, uint16_t, uint8_t) * @brief Set hid protocol @@ -72,6 +133,497 @@ static int hid_set_protocol( return 0; } +/** + * @fn void hid_enumerate_action_count_report(void*, libusb_hid_report_tag_t, uint32_t) + * @brief Method to enumerate action count report + * @param data + * @param tag + * @param value + */ +static void hid_enumerate_action_count_report( + void* data, + const libusb_hid_report_tag_t tag, + [[maybe_unused]] uint32_t value +) { + auto hid_report_action_count_t* report = ( hid_report_action_count_t* )data; + // handle tag + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + if ( !report->input ) { + report->count++; + report->input = true; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + if ( !report->output ) { + report->count++; + report->output = true; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + if ( !report->feature ) { + report->count++; + report->feature = true; + } + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + report->input = report->output = report->feature = false; + default: + break; + } +} + +/** + * @fn void hid_enumerate_action_count_field_process(hid_report_field_t*, uint32_t, libusb_hid_report_type_t) + * @brief Wrapper to enumerate action count field + * @param field + * @param value + * @param type + */ +static void hid_enumerate_action_count_field_process( + hid_report_field_t* field, + uint32_t value, + const libusb_hid_report_type_t type +) { + hid_report_field_data_t* field_data = NULL; + for ( size_t idx = 0; idx < field->current; idx++ ) { + if ( + field->data[ idx ].report_id == field->report + && field->data[ idx ].report_type == type + ) { + field_data = &field->data[ idx ]; + break; + } + } + if ( ! field_data ) { + field_data = &field->data[ field->current++ ]; + field_data->report_id = field->report; + field_data->field_count = 0; + field_data->report_type = type; + } + void* v = &value; + if ( ( ( libusb_hid_main_item_t* )v )->variable ) { + field_data->field_count += ( uint8_t )field->count; + } else { + field_data->field_count++; + } +} + +/** + * @fn void hid_enumerate_action_count_field(void*, libusb_hid_report_tag_t, uint32_t) + * @brief Method to enumerate action count fields + * @param data + * @param tag + * @param value + */ +static void hid_enumerate_action_count_field( + void* data, + const libusb_hid_report_tag_t tag, + const uint32_t value +) { + auto hid_report_field_t* field = ( hid_report_field_t* )data; + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: + field->count = value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + field->report = ( uint8_t )value; + break; + default: + break; + } +} + +/** + * @fn void hid_enumerate_action_add_field_process(hid_field_t*, uint32_t, libusb_hid_report_type_t) + * @brief Wrapper to process enumerate action add field + * @param field + * @param value + * @param type + */ +static void hid_enumerate_action_add_field_process( + hid_field_t* field, + const uint32_t value, + const libusb_hid_report_type_t type +) { + // try to find report from result + libusb_hid_parser_report_t* report = NULL; + for ( uint32_t idx = 0; idx < field->result->report_count; idx++ ) { + EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->id = %"PRIu8"\r\n", + idx, field->result->report[ idx ]->id ) + EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->type = %d\r\n", + idx, field->result->report[ idx ]->type ) + if ( + field->result->report[ idx ]->id == field->report + && field->result->report[ idx ]->type == type + ) { + report = field->result->report[ idx ]; + break; + } + } + // handle no report found + if ( ! report ) { + STARTUP_PRINT( "Report not found for %"PRIu8" / %d\r\n", + field->report, type ) + return; + } + // loop while field count is greater than 0 + while ( field->count > 0 ) { + // extract val + uint32_t val; + memcpy( &val, field->usage, sizeof( val ) ); + // handle first iteration + if ( val == 0xffffffff ) { + field->usage++; + } + memcpy( &report->fields[ report->field_count ].attribute, &value, sizeof( uint32_t ) ); + report->fields[ report->field_count ].count = ( uint8_t)( report->fields[ report->field_count ].attribute.variable ? 1 : field->count ); + report->fields[ report->field_count ].logical_maximum = field->logical_maximum; + report->fields[ report->field_count ].logical_minimum = field->logical_minimum; + report->fields[ report->field_count ].offset = report->report_length; + report->fields[ report->field_count ].physical_maximum = field->physical_maximum; + report->fields[ report->field_count ].physical_minimum = field->physical_minimum; + memcpy( &report->fields[ report->field_count ].physical_usage, &field->physical, sizeof( field->physical ) ); + report->fields[ report->field_count ].size = ( uint8_t )field->size; + memcpy( &report->fields[ report->field_count ].unit, &field->unit, sizeof( field->unit ) ); + report->fields[ report->field_count ].unit_exponent = field->unit_exponent; + if ( ( uint16_t )field->usage->page == LIBUSB_HID_USAGE_PAGE_USAGE_PAGE ) { + memcpy( &report->fields[ report->field_count ].usage, &field->usage[ -1 ], sizeof( uint32_t ) ); + if ( + field->usage->desktop == field->usage[ -1 ].desktop + || ! report->fields[ report->field_count ].attribute.variable + ) { + field->usage -= 2; + } else { + field->usage[ -1 ].desktop++; + } + } else { + memcpy( &report->fields[ report->field_count ].usage, field->usage--, sizeof( uint32_t ) ); + } + if (report->fields[ report->field_count ].attribute.variable ) { + field->count--; + report->report_length += report->fields[ report->field_count ].size; + report->fields[ report->field_count ].value.u32 = 0; + } else { + field->count = 0; + report->report_length += ( uint8_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count ); + report->fields[ report->field_count ].value.ptr = malloc( + ( size_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count / 8 ) ); + } + report->field_count++; + } + // set field usage 1 to 0 + constexpr uint32_t val = 0; + memcpy( &field->usage[ 1 ], &val, sizeof( uint32_t ) ); +} + +/** + * @fn void hid_enumerate_action_add_field(void*, libusb_hid_report_tag_t, uint32_t ) + * @brief Method to enumerate action add fields + * @param data + * @param tag + * @param value + */ +static void hid_enumerate_action_add_field( + void* data, + const libusb_hid_report_tag_t tag, + const uint32_t value +) { + auto hid_field_t* field = ( hid_field_t* )data; + + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_COLLECTION: + uint32_t val; + memcpy( &val, field->usage, sizeof( uint32_t ) ); + if ( 0xffffffff == val ) { + field->usage++; + } + switch ( ( libusb_hid_main_collection_t )value ) { + case LIBUSB_HID_MAIN_COLLECTION_APPLICATION: + memcpy( &field->result->application, field->usage, sizeof( uint32_t ) ); + break; + case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: + memcpy( &field->physical, field->usage, sizeof( uint32_t ) ); + break; + default: + break; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_END_COLLECTION: + switch ( ( libusb_hid_main_collection_t )value ) { + case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: + memset( &field->physical, 0, sizeof( uint32_t ) ); + break; + default: + break; + } + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_USAGE_PAGE: + field->page = ( libusb_hid_usage_page_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MINIMUM: + field->logical_minimum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MAXIMUM: + field->logical_maximum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MINIMUM: + field->physical_minimum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MAXIMUM: + field->physical_maximum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT_EXPONENT: + field->unit_exponent = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT: + memcpy( &field->unit, &value, sizeof( uint32_t ) ); + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_SIZE: + field->size = value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + field->report = ( uint8_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: + field->count = value; + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE: + field->usage++; + if ( value & 0xffff0000 ) { + memcpy( &field->usage, &value, sizeof( uint32_t ) ); + } else { + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = field->page; + } + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MINIMUM: + field->usage++; + if ( value & 0xffff0000 ) { + memcpy( &field->usage, &value, sizeof( uint32_t ) ); + } else { + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = field->page; + } + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MAXIMUM: + field->usage++; + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = LIBUSB_HID_USAGE_PAGE_USAGE_PAGE; + break; + default: + break; + } +} + +/** + * @fn void hid_enumerate_report(void*, const size_t, hid_report_action_t, void*) + * @brief Method to enumerate report with callback + * @param descriptor + * @param length + * @param action + * @param data + */ +static void hid_enumerate_report( + void* descriptor, + const size_t length, + const hid_report_action_t action, + void* data +) { + auto libusb_hid_report_item_t* item = ( libusb_hid_report_item_t* )descriptor; + libusb_hid_report_item_t* current = NULL; + size_t parsed_length = 0; + size_t current_index; + size_t current_length; + uint32_t value; + libusb_hid_report_tag_t tag; + + while ( parsed_length < length ) { + if ( ! current ) { + current = item; + current_index = 0; + current_length = 1 << ( current->size - 1 ); + value = 0; + tag = current->tag; + if ( current_length == 0 ) { + current = NULL; + } + } else { + if ( current->tag == LIBUSB_HID_REPORT_TAG_LONG && current_index < 2 ) { + if ( current_index == 0 ) { + current_length += *(uint8_t*)item; + } else { + tag |= ( uint16_t )*( uint8_t*)item << 8; + } + } else { + value |= ( uint32_t )( *( uint8_t* )item << ( 8 * current_index ) ); + } + if ( ++current_index == current_length ) { + current = NULL; + } + } + + if ( ! current ) { + if ( ( tag & 0x3 ) == 0x1 ) { + if ( current_length == 1 && ( value & 0x80 ) ) { + value |= 0xffffff00; + } else if ( current_length == 2 && ( value & 0x8000 ) ) { + value |= 0xffff0000; + } + } + action( data, tag, value ); + } + + item++; + parsed_length++; + } +} + +/** + * @fn int hid_parse_report_descriptor(libusb_hid_device_t*, void*, size_t) + * @brief Method to parse report descriptor + * @param device + * @param descriptor + * @param length + * @return + */ +static int hid_parse_report_descriptor( + libusb_hid_device_t* device, + void* descriptor, + const size_t length +) { + hid_report_action_count_t header = { + .count = 0, + .indent = 0, + .input = false, + .output = false, + .feature = false, + }; + hid_report_field_t* report_field = NULL; + hid_field_t* field = NULL; + + // enumerate action count + hid_enumerate_report( descriptor, length, hid_enumerate_action_count_report, &header ); + STARTUP_PRINT( "Found %"PRIu8" reports!\r\n", header.count ) + // allocate space + libusb_hid_parser_result_t* result = malloc( + sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); + if ( ! result ) { + STARTUP_PRINT( "Unable to allocate memory for parser result\r\n" ) + return ENOMEM; + } + // clear out + memset( result, 0, sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); + // allocate space for report field + report_field = malloc( sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); + if ( ! report_field ) { + STARTUP_PRINT( "Unable to allocate memory for report field\r\n" ) + free( result ); + return ENOMEM; + } + // clear out + memset( report_field, 0, sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); + // prepare data + result->report_count = header.count; + + // enumerate report fields + hid_enumerate_report( descriptor, length, hid_enumerate_action_count_field, report_field ); + for ( size_t idx = 0; idx < header.count; idx++ ) { + // allocate space for report + result->report[ idx ] = malloc( + sizeof( libusb_hid_parser_report_t ) + sizeof( libusb_hid_parser_fields_t ) * report_field->data[ idx ].field_count ); + // handle error + if ( ! result->report[ idx ] ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + // free report field and result + free( report_field ); + free( result ); + return ENOMEM; + } + // fill report + result->report[ idx ]->index = ( uint8_t )idx; + result->report[ idx ]->field_count = 0; + result->report[ idx ]->id = report_field->data[ idx ].report_id; + result->report[ idx ]->type = report_field->data[ idx ].report_type; + result->report[ idx ]->report_length = 0; + result->report[ idx ]->report_buffer = NULL; + } + // free again report fields + free( report_field ); + + // allocate space for field + field = malloc( sizeof( hid_field_t ) ); + if ( ! field ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + free( result ); + return ENOMEM; + } + // clear out + memset( field, 0, sizeof( hid_field_t ) ); + // set fields usage + field->usage = calloc(16, sizeof( libusb_hid_full_usage_t* ) ); + if ( ! field->usage ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + free( field ); + free( result ); + return ENOMEM; + } + // populate field + constexpr uint32_t val = 0xffffffff; + memcpy( field->usage, &val, sizeof( libusb_hid_full_usage_t ) ); + field->result = result; + // cache usage field + void* usage = field->usage; + // enumerate fields + hid_enumerate_report( descriptor, length, hid_enumerate_action_add_field, field ); + + // populate result to device + device->parser_result = result; + + // free usage field and field again + free( usage ); + free( field ); + + // return success + return 0; +} + /** * @fn void rpc_hid_attach(size_t, pid_t, size_t, size_t) * @brief Register rpc handler attach @@ -212,8 +764,9 @@ void rpc_hid_attach( return; } // find descriptor of hid - const libusb_hid_descriptor_t* descriptor = NULL; - uint32_t current_interface = message->interface_number + 1; + libusb_descriptor_header_t* original_header = header; + libusb_hid_descriptor_t* descriptor = NULL; + uint32_t interface_number = message->interface_number + 1; do { // handle end reached if ( ! header->descriptor_length ) { @@ -222,10 +775,10 @@ void rpc_hid_attach( // switch descriptor type switch ( header->descriptor_type ) { case LIBUSB_DESCRIPTOR_INTERFACE: - current_interface = ( ( libusb_interface_descriptor_t* )header )->number; + interface_number = ( ( libusb_interface_descriptor_t* )header )->number; break; case LIBUSB_DESCRIPTOR_HID: - if ( current_interface == message->interface_number ) { + if ( interface_number == message->interface_number ) { descriptor = ( libusb_hid_descriptor_t* )header; } break; @@ -234,7 +787,7 @@ void rpc_hid_attach( } // some debug output STARTUP_PRINT( "Descriptor %d with length %"PRIu8". Interface: %"PRIu32"\r\n", - header->descriptor_type, header->descriptor_length, current_interface ) + header->descriptor_type, header->descriptor_length, interface_number ) // handle descriptor found if ( descriptor ) { break; @@ -261,4 +814,93 @@ void rpc_hid_attach( // some debug output STARTUP_PRINT( "Detected hid device: %"PRIx16".%"PRIx16"\r\n", descriptor->hid_version >> 8, descriptor->hid_version & 0xff ) + // allocate hid device + libusb_hid_device_t* device = malloc( sizeof( *device ) ); + if ( ! device ) { + STARTUP_PRINT( "Could not allocate device structure\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + free( original_header ); + return; + } + // clear out stuff + memset( device, 0, sizeof( *device ) ); + // allocate report descriptor + void* report_descriptor = malloc( descriptor->optional[ 0 ].length ); + if ( ! report_descriptor ) { + STARTUP_PRINT( "Could not allocate reportDescriptor\r\n" ) + _syscall_rpc_cleanup(); + free( request ); + hid_destroy_device( device ); + free( original_header ); + return; + } + // clear out stuff + memset( report_descriptor, 0, descriptor->optional[ 0 ].length ); + // pure in descriptor + device->descriptor = descriptor; + // request descriptor + result = usb_get_descriptor( + message->device_number, + LIBUSB_DESCRIPTOR_HID_REPORT, + 0, + ( uint16_t )message->interface_number, + report_descriptor, + descriptor->optional[ 0 ].length, + descriptor->optional[ 0 ].length, + 1 + ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get hid report descriptor: %s\r\n", + strerror( result ) ) + _syscall_rpc_cleanup(); + free( request ); + hid_destroy_device( device ); + free( original_header ); + free( report_descriptor ); + return; + } + // parse report descriptor + result = hid_parse_report_descriptor( + device, report_descriptor, descriptor->optional[ 0 ].length ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to parse hid report descriptor: %s\r\n", + strerror( result ) ) + _syscall_rpc_cleanup(); + free( request ); + hid_destroy_device( device ); + free( original_header ); + free( report_descriptor ); + return; + } + + // populate device + device->parser_result->interface = ( uint8_t )message->interface_number; + // try to attach + result = handler_call_attach( + device->parser_result->application.desktop, + device, + message->device_number, + message->interface_number + ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to call attach device: %s\r\n", + strerror( result ) ); + _syscall_rpc_cleanup(); + free( request ); + hid_destroy_device( device ); + free( original_header ); + free( report_descriptor ); + return; + } + // append to handled devices + hid_append( device ); + // free up unnecessary stuff + free( request ); + free( original_header ); + free( report_descriptor ); + // call rpc cleanup since there is no return + _syscall_rpc_cleanup(); } diff --git a/bolthur/server/usb/device/hid/keyboard/main.c b/bolthur/server/usb/device/hid/keyboard/main.c index 788cc141..1cb4d0b3 100644 --- a/bolthur/server/usb/device/hid/keyboard/main.c +++ b/bolthur/server/usb/device/hid/keyboard/main.c @@ -71,7 +71,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // registering handler STARTUP_PRINT( "Registering handler at hid\r\n" ) - result = hid_register_handler( LIBHID_INTERFACE_TYPE_KEYBOARD ); + result = hid_register_handler( LIBUSB_HID_USAGE_PAGE_DESKTOP_KEYBOARD ); if ( 0 != result ) { STARTUP_PRINT( "Unable to register handler at hid\r\n" ) return -1; diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c index e2cf8f9c..609a620c 100644 --- a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c @@ -23,6 +23,7 @@ #include // local includes #include "../../rpc.h" +#include "../../global.h" #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" @@ -36,8 +37,38 @@ */ void rpc_keyboard_attach( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info ) { + // handle no data + if( ! data_info ) { + STARTUP_PRINT( "NO DATA PASSED!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // validate origin + if ( + origin != allowed_rpc_origin + && ! bolthur_rpc_validate_origin( origin, data_info ) + ) { + STARTUP_PRINT( "INVALID ORIGIN!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( + data_info, &data_size, true, NULL ); + if ( ! request ) { + STARTUP_PRINT( "ERROR WHILE FETCHING DATA: %s!\r\n", strerror( errno ) ) + _syscall_rpc_cleanup(); + return; + } + // allocate space for pull_request + //const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + /// FIXME: IMPLEMENT + STARTUP_PRINT( "KEYBOARD ATTACH FOLLOWING!\r\n" ) + free( request ); + _syscall_rpc_cleanup(); } diff --git a/bolthur/server/usb/device/hid/mouse/main.c b/bolthur/server/usb/device/hid/mouse/main.c index bf0da09a..0d7147f7 100644 --- a/bolthur/server/usb/device/hid/mouse/main.c +++ b/bolthur/server/usb/device/hid/mouse/main.c @@ -71,7 +71,7 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { // registering handler STARTUP_PRINT( "Registering handler at hid\r\n" ) - result = hid_register_handler( LIBHID_INTERFACE_TYPE_MOUSE ); + result = hid_register_handler( LIBUSB_HID_USAGE_PAGE_DESKTOP_MOUSE ); if ( 0 != result ) { STARTUP_PRINT( "Unable to register handler at hid\r\n" ) return -1; diff --git a/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c index 43d6ebc7..fbc5750e 100644 --- a/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c +++ b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c @@ -23,6 +23,7 @@ #include // local includes #include "../../rpc.h" +#include "../../global.h" #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" @@ -36,8 +37,38 @@ */ void rpc_mouse_attach( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, - [[maybe_unused]] size_t data_info, + pid_t origin, + size_t data_info, [[maybe_unused]] size_t response_info -) { + ) { + // handle no data + if( ! data_info ) { + STARTUP_PRINT( "NO DATA PASSED!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // validate origin + if ( + origin != allowed_rpc_origin + && ! bolthur_rpc_validate_origin( origin, data_info ) + ) { + STARTUP_PRINT( "INVALID ORIGIN!\r\n" ) + _syscall_rpc_cleanup(); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( + data_info, &data_size, true, NULL ); + if ( ! request ) { + STARTUP_PRINT( "ERROR WHILE FETCHING DATA: %s!\r\n", strerror( errno ) ) + _syscall_rpc_cleanup(); + return; + } + // allocate space for pull_request + //const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + /// FIXME: IMPLEMENT + STARTUP_PRINT( "MOUSE ATTACH FOLLOWING!\r\n" ) + free( request ); + _syscall_rpc_cleanup(); } diff --git a/bolthur/server/usb/device/hub/Makefile.am b/bolthur/server/usb/device/hub/Makefile.am index da45479d..7fab4163 100644 --- a/bolthur/server/usb/device/hub/Makefile.am +++ b/bolthur/server/usb/device/hub/Makefile.am @@ -15,5 +15,6 @@ hub_SOURCES = \ rpc/hub/deallocate.c \ rpc/hub/detach.c \ rpc/init.c \ + hub.c \ main.c hub_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/hub.c new file mode 100644 index 00000000..a3db2ca7 --- /dev/null +++ b/bolthur/server/usb/device/hub/hub.c @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "hub.h" +#include "../../../libusb.h" + +libusb_hub_device_t* hub_head = NULL; + +/** + * @fn void hub_append(libusb_hub_device_t*) + * @brief Append hub to handled list + * @param hub + */ +void hub_append( libusb_hub_device_t* hub ) { + // loop to last one + libusb_hub_device_t* current = hub_head; + libusb_hub_device_t* found = NULL; + while ( current ) { + found = current; + current = current->next; + } + // handle empty + if ( ! found ) { + hub_head = hub; + hub->prev = NULL; + hub->next = NULL; + return; + } + // attach to list + found->next = hub; + hub->prev = found; +} diff --git a/bolthur/server/usb/device/hub/hub.h b/bolthur/server/usb/device/hub/hub.h index 39584f23..5efbe584 100644 --- a/bolthur/server/usb/device/hub/hub.h +++ b/bolthur/server/usb/device/hub/hub.h @@ -20,6 +20,10 @@ #ifndef _HUB_H #define _HUB_H +#include "../../../libusb.h" + #define HUB_ENABLE_DEBUG 1 +void hub_append( libusb_hub_device_t* ); + #endif diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index ad7c73f8..ea710deb 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -826,8 +826,8 @@ void rpc_hub_attach( STARTUP_PRINT( "Checking port %"PRIu8"\r\n", port ) attach_hub_check_connection( message->device_number, hub, descriptor, port ); } - // free hub - free( hub ); + // store hub in linked list + hub_append( hub ); // free request free( request ); // cleanup rpc diff --git a/bolthur/server/usb/usbd/call.c b/bolthur/server/usb/usbd/call.c index da29780e..8d10f50a 100644 --- a/bolthur/server/usb/usbd/call.c +++ b/bolthur/server/usb/usbd/call.c @@ -80,12 +80,12 @@ int call_attach( libusb_device_t* dev, const uint32_t interface_number ) { } // attach is defined as first custom message bolthur_rpc_raise_generic( - RPC_CUSTOM_START, + GENERIC_ATTACH, handler, request, request_size, NULL, - RPC_CUSTOM_START, + GENERIC_ATTACH, request, request_size, 0, From 7923a4206d8916302a2f6f6b715abf2ca19a1633 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 15:25:07 +0200 Subject: [PATCH 028/144] - Adjusted process replace to use random area for executable instead of heap - Added defines for kernel area process replace start and end - Updated memory map --- bolthur/kernel/entry.h | 3 + bolthur/kernel/task/process.c | 81 +++++++++++++++++++++----- build-aux/platform/raspi/memory_map.md | 1 + 3 files changed, 71 insertions(+), 14 deletions(-) diff --git a/bolthur/kernel/entry.h b/bolthur/kernel/entry.h index e440454f..621799ed 100644 --- a/bolthur/kernel/entry.h +++ b/bolthur/kernel/entry.h @@ -29,6 +29,9 @@ #define KERNEL_AREA_START 0x80000000 #define KERNEL_AREA_END 0xFFFFFFFF + + #define KERNEL_AREA_PROCESS_REPLACE_START 0xF3041000 + #define KERNEL_AREA_PROCESS_REPLACE_END 0xFFFFFFFF #elif defined( ELF64 ) #define KERNEL_OFFSET 0xffffffff80000000 #endif diff --git a/bolthur/kernel/task/process.c b/bolthur/kernel/task/process.c index 4c31f759..e40abd76 100644 --- a/bolthur/kernel/task/process.c +++ b/bolthur/kernel/task/process.c @@ -39,6 +39,7 @@ #include "process.h" #include "thread.h" #include "stack.h" +#include "../entry.h" #include "../rpc/data.h" #include "../rpc/queue.h" #include "../rpc/generic.h" @@ -801,6 +802,55 @@ void task_process_prepare_kill( void* context, task_process_t* proc ) { event_enqueue( EVENT_PROCESS, EVENT_DETERMINE_ORIGIN( context ) ); } +/** + * @fn void unmap_replace_random(size_t) + * @brief Unmap replace random area + * @param size + */ +static void unmap_replace_random( const size_t size ) { + // allocate space + const uintptr_t end = KERNEL_AREA_PROCESS_REPLACE_START + size; + for ( + uintptr_t start = KERNEL_AREA_PROCESS_REPLACE_START; + start < end; + start += PAGE_SIZE + ) { + virt_unmap_address( virt_current_kernel_context, start, true ); + } +} + +/** + * @fn int map_replace_random(size_t) + * @brief Map replace random area + * @param size + * @return + */ +static int map_replace_random( const size_t size ) { + // allocate space + const uintptr_t end = KERNEL_AREA_PROCESS_REPLACE_START + size; + for ( + uintptr_t start = KERNEL_AREA_PROCESS_REPLACE_START; + start < end; + start += PAGE_SIZE + ) { + // map address + const bool result = virt_map_address_random( + virt_current_kernel_context, + start, + VIRT_MEMORY_TYPE_NORMAL_NC, + VIRT_PAGE_TYPE_READ | VIRT_PAGE_TYPE_WRITE + ); + // handle failure + if ( ! result ) { + // unmap random + unmap_replace_random( KERNEL_AREA_PROCESS_REPLACE_START - start ); + // return nomem + return -ENOMEM; + } + } + return 0; +} + /** * @fn int task_process_replace(task_process_t*, uintptr_t, const char**, const char**, void*) * @brief Replace current process with elf image @@ -811,8 +861,6 @@ void task_process_prepare_kill( void* context, task_process_t* proc ) { * @param env * @param context * @return - * - * @todo don't allocate kernel heap for elf application */ int task_process_replace( task_process_t* proc, @@ -821,7 +869,7 @@ int task_process_replace( const char** env, void* context ) { - bool replace_current_thread = task_thread_current_thread->process == proc; + const bool replace_current_thread = task_thread_current_thread->process == proc; #if defined( PRINT_PROCESS ) DEBUG_OUTPUT( "task_thread_current_thread->process = %p, proc = %p\r\n", @@ -854,13 +902,16 @@ int task_process_replace( #if defined( PRINT_PROCESS ) DEBUG_OUTPUT( "image_size = %#zx\r\n", image_size ) #endif - void* image = malloc( sizeof( char ) * image_size ); - // handle error - if ( ! image ) { + // map random place for image + const int result = map_replace_random( image_size ); + if ( 0 != result ) { free( tmp_argv ); free( tmp_env ); - return -ENOMEM; + return result; } + // set image + auto void* image = ( void* )KERNEL_AREA_PROCESS_REPLACE_START; + // copy over image #if defined( PRINT_PROCESS ) DEBUG_OUTPUT( "image = %p\r\n", image ) #endif @@ -870,7 +921,7 @@ int task_process_replace( if ( ! shared_memory_cleanup_process( proc ) ) { free( tmp_argv ); free( tmp_env ); - free( image ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -879,7 +930,7 @@ int task_process_replace( if ( ! virt_destroy_context( proc->virtual_context, true ) ) { free( tmp_argv ); free( tmp_env ); - free( image ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -908,7 +959,7 @@ int task_process_replace( if ( ! proc->thread_manager ) { free( tmp_argv ); free( tmp_env ); - free( image ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -916,7 +967,7 @@ int task_process_replace( if ( ! proc->thread_stack_manager ) { free( tmp_argv ); free( tmp_env ); - free( image ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -924,11 +975,11 @@ int task_process_replace( proc->current_thread_id = 0; // load elf image - uintptr_t init_entry = elf_load( ( uintptr_t )image, proc ); + const uintptr_t init_entry = elf_load( ( uintptr_t )image, proc ); if ( ! init_entry ) { free( tmp_argv ); free( tmp_env ); - free( image ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -938,6 +989,7 @@ int task_process_replace( if ( ! new_current ) { free( tmp_argv ); free( tmp_env ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } @@ -952,12 +1004,13 @@ int task_process_replace( if ( ! task_thread_push_arguments( new_current, tmp_argv, tmp_env ) ) { free( tmp_argv ); free( tmp_env ); + unmap_replace_random( image_size ); task_process_prepare_kill( context, proc ); return -ENOMEM; } // free temporary stuff - free( image ); + unmap_replace_random( image_size ); free( tmp_argv ); free( tmp_env ); diff --git a/build-aux/platform/raspi/memory_map.md b/build-aux/platform/raspi/memory_map.md index 9e827a1e..16151bb5 100644 --- a/build-aux/platform/raspi/memory_map.md +++ b/build-aux/platform/raspi/memory_map.md @@ -16,6 +16,7 @@ kernel area: 0xF2000000 - 0xF2FFFFFF => gpio peripheral 0xF3000000 - 0xF303FFFF => local peripheral ( raspi 2 / 3 only ) 0xF3040000 - 0xF3040FFF => mailbox area + 00xF341000 - 0xFFFFFFFF => process replace area ``` ## 64 bit ( v8 ) From 0848435041d2357cabd2f05fe93e98c8ea93db30 Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 15:29:42 +0200 Subject: [PATCH 029/144] - Fixed hid usage page enum for point and mouse - Moved typedefs from hid attach into header hid of process hid - Moved hid destroy device into hid.c and added removal from hid list - Added save of device_number within hid device and hub device - Added documentation to attach hub functions before moving them - Added cache of descriptor in hub device instance - Added free of descriptor on error within hub attach - Added structures and enums for keyboard and mouse - Implemented list of keyboard and list of mouse to specific driver with append method --- bolthur/server/libusb.h | 76 ++++++++++- bolthur/server/usb/device/hid/hid/hid.c | 35 +++++ bolthur/server/usb/device/hid/hid/hid.h | 41 ++++++ .../usb/device/hid/hid/rpc/hid/attach.c | 61 +-------- .../usb/device/hid/keyboard/Makefile.am | 1 + .../server/usb/device/hid/keyboard/keyboard.c | 47 +++++++ .../server/usb/device/hid/keyboard/keyboard.h | 29 ++++ .../server/usb/device/hid/mouse/Makefile.am | 3 +- bolthur/server/usb/device/hid/mouse/mouse.c | 47 +++++++ bolthur/server/usb/device/hid/mouse/mouse.h | 29 ++++ .../server/usb/device/hub/rpc/hub/attach.c | 124 ++++++++++++++---- 11 files changed, 405 insertions(+), 88 deletions(-) create mode 100644 bolthur/server/usb/device/hid/keyboard/keyboard.c create mode 100644 bolthur/server/usb/device/hid/keyboard/keyboard.h create mode 100644 bolthur/server/usb/device/hid/mouse/mouse.c create mode 100644 bolthur/server/usb/device/hid/mouse/mouse.h diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index eb5ce071..c6818c92 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -556,6 +556,9 @@ typedef struct libusb_hub_device { uint32_t max_children; libusb_hub_port_full_status_t port_status[ 255 ]; uint32_t children[ 255 ]; + + uint32_t device_number; + libusb_hub_device_t* next; libusb_hub_device_t* prev; } libusb_hub_device_t; @@ -645,8 +648,8 @@ typedef enum { } libusb_hid_usage_page_t; typedef enum { - LIBUSB_HID_USAGE_PAGE_DESKTOP_POINT = 0, - LIBUSB_HID_USAGE_PAGE_DESKTOP_MOUSE = 1, + LIBUSB_HID_USAGE_PAGE_DESKTOP_POINT = 1, + LIBUSB_HID_USAGE_PAGE_DESKTOP_MOUSE = 2, LIBUSB_HID_USAGE_PAGE_DESKTOP_JOYSTICK = 4, LIBUSB_HID_USAGE_PAGE_DESKTOP_GAMEPAD = 5, LIBUSB_HID_USAGE_PAGE_DESKTOP_KEYBOARD = 6, @@ -793,10 +796,79 @@ typedef struct libusb_hid_device { pid_t device_detached_handler; pid_t device_deallocate_handler; + uint32_t device_number; + libusb_hid_device_t* next; libusb_hid_device_t* prev; } libusb_hid_device_t; +typedef struct __packed { + bool left_control : 1; + bool left_shift : 1; + bool left_alt : 1; + bool left_gui : 1; + bool right_control : 1; + bool right_shift : 1; + bool right_alt : 1; + bool right_gui : 1; +} libusb_keyboard_modifier_t; + +typedef struct __packed { + bool num_lock : 1; + bool caps_lock : 1; + bool scroll_lock : 1; + bool compose : 1; + bool kana : 1; + bool power : 1; + bool mute : 1; + bool shift : 1; +} libusb_keyboard_led_t; + +typedef struct libusb_keyboard_device libusb_keyboard_device_t; +typedef struct libusb_keyboard_device { + libusb_driver_data_header header; + uint32_t index; + uint32_t key_count; + uint16_t max_key_down[ 6 ]; + libusb_keyboard_modifier_t modifier; + libusb_keyboard_led_t led; + libusb_hid_parser_fields_t* led_field[ 8 ]; + libusb_hid_parser_fields_t* key_field[ 8 + 1 ]; + libusb_hid_parser_report_t* led_report; + libusb_hid_parser_report_t* key_report; + + uint32_t device_number; + + libusb_keyboard_device_t* next; + libusb_keyboard_device_t* prev; +} libusb_keyboard_device_t; + +typedef enum { + LIBUSB_MOUSE_DEVICE_BUTTON_LEFT, + LIBUSB_MOUSE_DEVICE_BUTTON_RIGHT, + LIBUSB_MOUSE_DEVICE_BUTTON_MIDDLE, + LIBUSB_MOUSE_DEVICE_BUTTON_SIDE, + LIBUSB_MOUSE_DEVICE_BUTTON_EXTRA, +} libusb_mouse_device_button_t; + +typedef struct libusb_mouse_device libusb_mouse_device_t; +typedef struct libusb_mouse_device { + libusb_driver_data_header header; + uint32_t index; + + uint8_t button_state; + int16_t mouse_x; + int16_t mouse_y; + int16_t wheel; + + libusb_hid_parser_report_t* mouse_report; + + uint32_t device_number; + + libusb_mouse_device_t* next; + libusb_mouse_device_t* prev; +} libusb_mouse_device_t; + // enable warnings again #pragma GCC diagnostic pop diff --git a/bolthur/server/usb/device/hid/hid/hid.c b/bolthur/server/usb/device/hid/hid/hid.c index 1d48a64a..27a413de 100644 --- a/bolthur/server/usb/device/hid/hid/hid.c +++ b/bolthur/server/usb/device/hid/hid/hid.c @@ -17,10 +17,45 @@ * along with bolthur/kernel. If not, see . */ +#include #include "hid.h" libusb_hid_device_t* hid_head = NULL; +/** + * @fn void hid_destroy_device(libusb_hid_device_t*) + * @brief Helper to destroy hid device + * @param device + */ +void hid_destroy_device( libusb_hid_device_t* device ) { + // handle invalid device + if ( ! device ) { + return; + } + // remove from list + if ( device->prev ) { + device->prev->next = device->next; + } + if ( device->next ) { + device->next->prev = device->prev; + } + // handle parser result set + if ( device->parser_result ) { + // free possible reports + for ( size_t idx = 0; idx < device->parser_result->report_count; idx++ ) { + // handle report allocated + if ( device->parser_result->report[ idx ] ) { + // free report + free( device->parser_result->report[ idx ] ); + } + } + // free parser result + free( device->parser_result ); + } + // free device + free( device ); +} + /** * @fn void hid_append(libusb_hid_device_t*) * @brief Append hid to handled devices diff --git a/bolthur/server/usb/device/hid/hid/hid.h b/bolthur/server/usb/device/hid/hid/hid.h index d0b4a3d7..813c6669 100644 --- a/bolthur/server/usb/device/hid/hid/hid.h +++ b/bolthur/server/usb/device/hid/hid/hid.h @@ -20,8 +20,49 @@ #ifndef _HID_H #define _HID_H +#include #include "../../../../libusb.h" +typedef struct { + uint8_t count; + uint8_t indent; + bool input; + bool output; + bool feature; +} hid_report_action_count_t; + +typedef struct { + uint8_t report_id; + uint8_t field_count; + libusb_hid_report_type_t report_type; +} hid_report_field_data_t; + +typedef struct { + uint32_t count; + uint8_t current; + uint8_t report; + hid_report_field_data_t data[]; +} hid_report_field_t; + +typedef struct { + libusb_hid_parser_result_t* result; + uint32_t count; + uint32_t size; + libusb_hid_full_usage_t* usage; + libusb_hid_full_usage_t physical; + int32_t logical_minimum; + int32_t logical_maximum; + int32_t physical_minimum; + int32_t physical_maximum; + libusb_hid_unit_t unit; + int32_t unit_exponent; + libusb_hid_usage_page_t page; + uint8_t report; +} hid_field_t; + +typedef void( *hid_report_action_t )( void* data, libusb_hid_report_tag_t tag, uint32_t value ); + +void hid_destroy_device( libusb_hid_device_t* ); void hid_append( libusb_hid_device_t* ); #endif diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c index bab07ba7..b9123775 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -29,65 +29,6 @@ #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" -typedef struct { - uint8_t count; - uint8_t indent; - bool input; - bool output; - bool feature; -} hid_report_action_count_t; - -typedef struct { - uint8_t report_id; - uint8_t field_count; - libusb_hid_report_type_t report_type; -} hid_report_field_data_t; - -typedef struct { - uint32_t count; - uint8_t current; - uint8_t report; - hid_report_field_data_t data[]; -} hid_report_field_t; - -typedef struct { - libusb_hid_parser_result_t* result; - uint32_t count; - uint32_t size; - libusb_hid_full_usage_t* usage; - libusb_hid_full_usage_t physical; - int32_t logical_minimum; - int32_t logical_maximum; - int32_t physical_minimum; - int32_t physical_maximum; - libusb_hid_unit_t unit; - int32_t unit_exponent; - libusb_hid_usage_page_t page; - uint8_t report; -} hid_field_t; - -typedef void( *hid_report_action_t )( void* data, libusb_hid_report_tag_t tag, uint32_t value ); - -/** - * @fn void hid_destroy_device(libusb_hid_device_t*) - * @brief Helper to destroy hid device - * @param device - */ -static void hid_destroy_device( libusb_hid_device_t* device ) { - if ( ! device ) { - return; - } - if ( device->parser_result ) { - for ( size_t idx = 0; idx < device->parser_result->report_count; idx++ ) { - if ( device->parser_result->report[ idx ] ) { - free( device->parser_result->report[ idx ] ); - } - } - free( device->parser_result ); - } - free( device ); -} - /** * @fn int hid_set_protocol(uint32_t, uint16_t, uint8_t) * @brief Set hid protocol @@ -825,6 +766,8 @@ void rpc_hid_attach( } // clear out stuff memset( device, 0, sizeof( *device ) ); + // populate device + device->device_number = message->device_number; // allocate report descriptor void* report_descriptor = malloc( descriptor->optional[ 0 ].length ); if ( ! report_descriptor ) { diff --git a/bolthur/server/usb/device/hid/keyboard/Makefile.am b/bolthur/server/usb/device/hid/keyboard/Makefile.am index ac61c0f1..a1dc95ab 100644 --- a/bolthur/server/usb/device/hid/keyboard/Makefile.am +++ b/bolthur/server/usb/device/hid/keyboard/Makefile.am @@ -13,5 +13,6 @@ keyboard_SOURCES = \ rpc/keyboard/deallocate.c \ rpc/keyboard/detach.c \ rpc/init.c \ + keyboard.c \ main.c keyboard_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/keyboard/keyboard.c b/bolthur/server/usb/device/hid/keyboard/keyboard.c new file mode 100644 index 00000000..7edb41e0 --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/keyboard.c @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "keyboard.h" + +libusb_keyboard_device_t* keyboard_head = NULL; + +/** + * @fn void keyboard_append(libusb_keyboard_device_t*) + * @brief Append keyboard to handled list + * @param keyboard + */ +void keyboard_append( libusb_keyboard_device_t* keyboard ) { + // loop to last one + libusb_keyboard_device_t* current = keyboard_head; + libusb_keyboard_device_t* found = NULL; + while ( current ) { + found = current; + current = current->next; + } + // handle empty + if ( ! found ) { + keyboard_head = keyboard; + keyboard->prev = NULL; + keyboard->next = NULL; + return; + } + // attach to list + found->next = keyboard; + keyboard->prev = found; +} diff --git a/bolthur/server/usb/device/hid/keyboard/keyboard.h b/bolthur/server/usb/device/hid/keyboard/keyboard.h new file mode 100644 index 00000000..997c93bc --- /dev/null +++ b/bolthur/server/usb/device/hid/keyboard/keyboard.h @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _KEYBOARD_H +#define _KEYBOARD_H + +#include "../../../../libusb.h" + +#define KEYBOARD_ENABLE_DEBUG 1 + +void keyboard_append( libusb_keyboard_device_t* ); + +#endif diff --git a/bolthur/server/usb/device/hid/mouse/Makefile.am b/bolthur/server/usb/device/hid/mouse/Makefile.am index 6362e919..98b9cd6b 100644 --- a/bolthur/server/usb/device/hid/mouse/Makefile.am +++ b/bolthur/server/usb/device/hid/mouse/Makefile.am @@ -13,5 +13,6 @@ mouse_SOURCES = \ rpc/mouse/deallocate.c \ rpc/mouse/detach.c \ rpc/init.c \ - main.c + main.c \ + mouse.c mouse_LDFLAGS = -all-static --static diff --git a/bolthur/server/usb/device/hid/mouse/mouse.c b/bolthur/server/usb/device/hid/mouse/mouse.c new file mode 100644 index 00000000..130f2b92 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/mouse.c @@ -0,0 +1,47 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#include "mouse.h" + +libusb_mouse_device_t* mouse_head = NULL; + +/** + * @fn void mouse_append(libusb_mouse_device_t*) + * @brief Append mouse to handled list + * @param mouse + */ +void mouse_append( libusb_mouse_device_t* mouse ) { + // loop to last one + libusb_mouse_device_t* current = mouse_head; + libusb_mouse_device_t* found = NULL; + while ( current ) { + found = current; + current = current->next; + } + // handle empty + if ( ! found ) { + mouse_head = mouse; + mouse->prev = NULL; + mouse->next = NULL; + return; + } + // attach to list + found->next = mouse; + mouse->prev = found; +} diff --git a/bolthur/server/usb/device/hid/mouse/mouse.h b/bolthur/server/usb/device/hid/mouse/mouse.h new file mode 100644 index 00000000..5b123173 --- /dev/null +++ b/bolthur/server/usb/device/hid/mouse/mouse.h @@ -0,0 +1,29 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +#ifndef _MOUSE_H +#define _MOUSE_H + +#include "../../../../libusb.h" + +#define MOUSE_ENABLE_DEBUG 1 + +void mouse_append( libusb_mouse_device_t* ); + +#endif diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index ea710deb..5ddc0965 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -28,6 +28,11 @@ #include "../../../../../libusbd.h" #include "../../../../../../library/usb/usb.h" +/** + * @fn void custom_nanosleep(const struct timespec*) + * @brief Custom nanosleep implementation + * @param rqtp + */ static void custom_nanosleep( const struct timespec* rqtp ) { if ( 0 > rqtp->tv_nsec ) { errno = EINVAL; @@ -54,6 +59,13 @@ static void custom_nanosleep( const struct timespec* rqtp ) { //#endif } +/** + * @fn int attach_hub_read_descriptor(uint32_t, void**) + * @brief Read up descriptor + * @param device_number + * @param descriptor + * @return + */ static int attach_hub_read_descriptor( const uint32_t device_number, void** descriptor ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -108,6 +120,13 @@ static int attach_hub_read_descriptor( const uint32_t device_number, void** desc return 0; } +/** + * @fn int attach_hub_get_status(uint32_t, libusb_hub_device_t*) + * @brief Function to get hub status + * @param device_number + * @param hub_device + * @return + */ static int attach_hub_get_status( const uint32_t device_number, libusb_hub_device_t* hub_device @@ -153,6 +172,15 @@ static int attach_hub_get_status( return 0; } +/** + * @fn int attach_hub_change_port_feature(uint32_t, libusb_hub_port_feature_t, uint8_t, bool) + * @brief Method to change port feature + * @param device_number + * @param feature + * @param port + * @param set + * @return + */ static int attach_hub_change_port_feature( const uint32_t device_number, const libusb_hub_port_feature_t feature, @@ -181,10 +209,16 @@ static int attach_hub_change_port_feature( ); } +/** + * @fn int attach_hub_power_on(uint32_t, libusb_hub_device_t*) + * @brief Function to power on hub + * @param device_number + * @param hub_device + * @return + */ static int attach_hub_power_on( const uint32_t device_number, - const libusb_hub_device_t* hub_device, - const libusb_hub_descriptor_t* descriptor + const libusb_hub_device_t* hub_device ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -212,7 +246,7 @@ static int attach_hub_power_on( } } // milliseconds to sleep - const long milliseconds = descriptor->power_good_delay * 2; + const long milliseconds = hub_device->descriptor->power_good_delay * 2; STARTUP_PRINT( "sleeping %ld milliseconds\r\n", milliseconds ) // sleep a bit custom_nanosleep( &(struct timespec){ @@ -223,6 +257,14 @@ static int attach_hub_power_on( return 0; } +/** + * @fn int attach_hub_get_port_status(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Function to get port status of hub + * @param device_number + * @param hub + * @param port + * @return + */ static int attach_hub_get_port_status( const uint32_t device_number, libusb_hub_device_t* hub, @@ -269,6 +311,14 @@ static int attach_hub_get_port_status( return 0; } +/** + * @fn int attach_hub_port_reset(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Method to reset hub port + * @param device_number + * @param device_data + * @param port + * @return + */ static int attach_hub_port_reset( const uint32_t device_number, libusb_hub_device_t* device_data, @@ -366,6 +416,14 @@ static int attach_hub_port_reset( return 0; } +/** + * @fn int attach_hub_port_connection_changed(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Method to handle connection change of port + * @param device_number + * @param device_data + * @param port + * @return + */ static int attach_hub_port_connection_changed( const uint32_t device_number, libusb_hub_device_t* device_data, @@ -451,10 +509,17 @@ static int attach_hub_port_connection_changed( return 0; } +/** + * @fn int attach_hub_check_connection(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Function to check hub connection + * @param device_number + * @param device_data + * @param port + * @return + */ static int attach_hub_check_connection( const uint32_t device_number, libusb_hub_device_t* device_data, - const libusb_hub_descriptor_t* descriptor, const uint8_t port ) { // cache hub device @@ -550,7 +615,7 @@ static int attach_hub_check_connection( #endif } // power on hub - result = attach_hub_power_on( device_number, device_data, descriptor ); + result = attach_hub_power_on( device_number, device_data ); // handle error if ( 0 != result ) { // debug output @@ -588,7 +653,7 @@ static int attach_hub_check_connection( */ void rpc_hub_attach( [[maybe_unused]] size_t type, - [[maybe_unused]] pid_t origin, + pid_t origin, size_t data_info, [[maybe_unused]] size_t response_info ) { @@ -693,29 +758,32 @@ void rpc_hub_attach( free( request ); return; } - // populate hub max children - hub->max_children = descriptor->port_count; + // populate hub max children and device number + hub->descriptor = descriptor; + hub->max_children = hub->descriptor->port_count; + hub->device_number = message->device_number; STARTUP_PRINT( "hub->max_children = %"PRIu32"\r\n", hub->max_children ) // validate power switching mode if ( - LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.power_switching_mode - && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.power_switching_mode - && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != descriptor->attributes.power_switching_mode + LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub->descriptor->attributes.power_switching_mode + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub->descriptor->attributes.power_switching_mode + && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != hub->descriptor->attributes.power_switching_mode ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unknown power type %d on %s\r\n", - descriptor->attributes.power_switching_mode, + hub->descriptor->attributes.power_switching_mode, usb_get_description( message->device_number ) ) #endif _syscall_rpc_cleanup(); + free( descriptor ); free( hub ); free( request ); return; } // some debug output #if defined( HUB_ENABLE_DEBUG ) - switch ( descriptor->attributes.power_switching_mode ) { + switch ( hub->descriptor->attributes.power_switching_mode ) { case LIBUSB_HUB_PORT_CONTROL_GLOBAL: STARTUP_PRINT( "Power mode is global\r\n" ) break; @@ -726,7 +794,7 @@ void rpc_hub_attach( STARTUP_PRINT( "Power mode is no power switching supported\r\n" ) break; } - if ( descriptor->attributes.compound ) { + if ( hub->descriptor->attributes.compound ) { STARTUP_PRINT( "Hub nature is compound\r\n" ) } else { STARTUP_PRINT( "Hub nature is standalone\r\n" ) @@ -734,24 +802,25 @@ void rpc_hub_attach( #endif // validate over current protection if ( - LIBUSB_HUB_PORT_CONTROL_GLOBAL != descriptor->attributes.over_current_protection - && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != descriptor->attributes.over_current_protection - && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != descriptor->attributes.over_current_protection + LIBUSB_HUB_PORT_CONTROL_GLOBAL != hub->descriptor->attributes.over_current_protection + && LIBUSB_HUB_PORT_CONTROL_INDIVIDUAL != hub->descriptor->attributes.over_current_protection + && LIBUSB_HUB_PORT_CONTROL_NO_POWER_SWITCHING != hub->descriptor->attributes.over_current_protection ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unknown hub over current type %d on %s\r\n", - descriptor->attributes.power_switching_mode, + hub->descriptor->attributes.power_switching_mode, usb_get_description( message->device_number ) ) #endif _syscall_rpc_cleanup(); + free( descriptor ); free( hub ); free( request ); return; } // some debug output #if defined( HUB_ENABLE_DEBUG ) - switch ( descriptor->attributes.over_current_protection ) { + switch ( hub->descriptor->attributes.over_current_protection ) { case LIBUSB_HUB_PORT_CONTROL_GLOBAL: STARTUP_PRINT( "Hub over current protection is global\r\n" ) break; @@ -762,9 +831,9 @@ void rpc_hub_attach( STARTUP_PRINT( "Hub has no over current protection\r\n" ) break; } - STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", descriptor->power_good_delay * 2 ) - STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", descriptor->maximum_hub_power * 2 ) - STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", descriptor->port_count ) + STARTUP_PRINT( "Hub power to good: %"PRIu8"ms\r\n", hub->descriptor->power_good_delay * 2 ) + STARTUP_PRINT( "Hub current required: %"PRIu8"mA.\r\n", hub->descriptor->maximum_hub_power * 2 ) + STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", hub->descriptor->port_count ) #endif // retrieve status result = attach_hub_get_status( message->device_number, hub ); @@ -776,6 +845,7 @@ void rpc_hub_attach( usb_get_description( message->device_number ), strerror( result ) ) #endif _syscall_rpc_cleanup(); + free( descriptor ); free( hub ); free( request ); return; @@ -790,13 +860,14 @@ void rpc_hub_attach( !status->status.over_current ? "No" : "Yes" ) #endif // power on hub - result = attach_hub_power_on( message->device_number, hub, descriptor ); + result = attach_hub_power_on( message->device_number, hub ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) STARTUP_PRINT( "Unable to power on hub!\r\n" ) #endif _syscall_rpc_cleanup(); + free( descriptor ); free( hub ); free( request ); return; @@ -810,6 +881,7 @@ void rpc_hub_attach( usb_get_description( message->device_number ), strerror( result ) ) #endif _syscall_rpc_cleanup(); + free( descriptor ); free( hub ); free( request ); return; @@ -822,9 +894,9 @@ void rpc_hub_attach( !status->status.over_current ? "No" : "Yes" ) #endif // check for connection - for ( uint8_t port = 0; port < hub->max_children; port++ ) { - STARTUP_PRINT( "Checking port %"PRIu8"\r\n", port ) - attach_hub_check_connection( message->device_number, hub, descriptor, port ); + for ( uint32_t port = 0; port < hub->max_children; port++ ) { + STARTUP_PRINT( "Checking port %"PRIu32"\r\n", port ) + attach_hub_check_connection( message->device_number, hub, ( uint8_t )port ); } // store hub in linked list hub_append( hub ); From 0300f70c7c72c046557c4bf3c720ed9a665c201a Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 18:10:07 +0200 Subject: [PATCH 030/144] - Moved static hid attach functions into hid.c - Moved static hub attach functions into hub.c --- bolthur/server/usb/device/hid/hid/hid.c | 542 +++++++++++++++ bolthur/server/usb/device/hid/hid/hid.h | 8 + .../usb/device/hid/hid/rpc/hid/attach.c | 536 --------------- bolthur/server/usb/device/hub/hub.c | 619 +++++++++++++++++ bolthur/server/usb/device/hub/hub.h | 8 + .../server/usb/device/hub/rpc/hub/attach.c | 625 +----------------- 6 files changed, 1182 insertions(+), 1156 deletions(-) diff --git a/bolthur/server/usb/device/hid/hid/hid.c b/bolthur/server/usb/device/hid/hid/hid.c index 27a413de..aeb58e23 100644 --- a/bolthur/server/usb/device/hid/hid/hid.c +++ b/bolthur/server/usb/device/hid/hid/hid.c @@ -18,7 +18,13 @@ */ #include +#include +#include +#include #include "hid.h" +#include "../../../../libusb.h" +#include "../../../../libusbd.h" +#include "../../../../../library/usb/usb.h" libusb_hid_device_t* hid_head = NULL; @@ -56,6 +62,542 @@ void hid_destroy_device( libusb_hid_device_t* device ) { free( device ); } +/** + * @fn int hid_set_protocol(uint32_t, uint16_t, uint8_t) + * @brief Set hid protocol + * @param device_number + * @param interface + * @param protocol + * @return + */ +int hid_set_protocol( + const uint32_t device_number, + const uint16_t interface, + const uint8_t protocol +) { + uint32_t last_transfer; + libusb_transfer_error_t error; + // perform control message + const int result = usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_OUT, + NULL, + 0, + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_SET_PROTOCOL, + .type = 0x21, + .index = interface, + .value = protocol, + .length = 0, + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); + // handle error + if ( 0 != result ) { + return result; + } + // handle error + if ( error != LIBUSB_TRANSFER_ERROR_NO_ERROR ) { + return EIO; + } + // return success + return 0; +} + +/** + * @fn void hid_enumerate_action_count_report(void*, libusb_hid_report_tag_t, uint32_t) + * @brief Method to enumerate action count report + * @param data + * @param tag + * @param value + */ +void hid_enumerate_action_count_report( + void* data, + const libusb_hid_report_tag_t tag, + [[maybe_unused]] uint32_t value +) { + auto hid_report_action_count_t* report = ( hid_report_action_count_t* )data; + // handle tag + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + if ( !report->input ) { + report->count++; + report->input = true; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + if ( !report->output ) { + report->count++; + report->output = true; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + if ( !report->feature ) { + report->count++; + report->feature = true; + } + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + report->input = report->output = report->feature = false; + default: + break; + } +} + +/** + * @fn void hid_enumerate_action_count_field_process(hid_report_field_t*, uint32_t, libusb_hid_report_type_t) + * @brief Wrapper to enumerate action count field + * @param field + * @param value + * @param type + */ +void hid_enumerate_action_count_field_process( + hid_report_field_t* field, + uint32_t value, + const libusb_hid_report_type_t type +) { + hid_report_field_data_t* field_data = NULL; + for ( size_t idx = 0; idx < field->current; idx++ ) { + if ( + field->data[ idx ].report_id == field->report + && field->data[ idx ].report_type == type + ) { + field_data = &field->data[ idx ]; + break; + } + } + if ( ! field_data ) { + field_data = &field->data[ field->current++ ]; + field_data->report_id = field->report; + field_data->field_count = 0; + field_data->report_type = type; + } + void* v = &value; + if ( ( ( libusb_hid_main_item_t* )v )->variable ) { + field_data->field_count += ( uint8_t )field->count; + } else { + field_data->field_count++; + } +} + +/** + * @fn void hid_enumerate_action_count_field(void*, libusb_hid_report_tag_t, uint32_t) + * @brief Method to enumerate action count fields + * @param data + * @param tag + * @param value + */ +void hid_enumerate_action_count_field( + void* data, + const libusb_hid_report_tag_t tag, + const uint32_t value +) { + auto hid_report_field_t* field = ( hid_report_field_t* )data; + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: + field->count = value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + field->report = ( uint8_t )value; + break; + default: + break; + } +} + +/** + * @fn void hid_enumerate_action_add_field_process(hid_field_t*, uint32_t, libusb_hid_report_type_t) + * @brief Wrapper to process enumerate action add field + * @param field + * @param value + * @param type + */ +void hid_enumerate_action_add_field_process( + hid_field_t* field, + const uint32_t value, + const libusb_hid_report_type_t type +) { + // try to find report from result + libusb_hid_parser_report_t* report = NULL; + for ( uint32_t idx = 0; idx < field->result->report_count; idx++ ) { + EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->id = %"PRIu8"\r\n", + idx, field->result->report[ idx ]->id ) + EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->type = %d\r\n", + idx, field->result->report[ idx ]->type ) + if ( + field->result->report[ idx ]->id == field->report + && field->result->report[ idx ]->type == type + ) { + report = field->result->report[ idx ]; + break; + } + } + // handle no report found + if ( ! report ) { + STARTUP_PRINT( "Report not found for %"PRIu8" / %d\r\n", + field->report, type ) + return; + } + // loop while field count is greater than 0 + while ( field->count > 0 ) { + // extract val + uint32_t val; + memcpy( &val, field->usage, sizeof( val ) ); + // handle first iteration + if ( val == 0xffffffff ) { + field->usage++; + } + memcpy( &report->fields[ report->field_count ].attribute, &value, sizeof( uint32_t ) ); + report->fields[ report->field_count ].count = ( uint8_t)( report->fields[ report->field_count ].attribute.variable ? 1 : field->count ); + report->fields[ report->field_count ].logical_maximum = field->logical_maximum; + report->fields[ report->field_count ].logical_minimum = field->logical_minimum; + report->fields[ report->field_count ].offset = report->report_length; + report->fields[ report->field_count ].physical_maximum = field->physical_maximum; + report->fields[ report->field_count ].physical_minimum = field->physical_minimum; + memcpy( &report->fields[ report->field_count ].physical_usage, &field->physical, sizeof( field->physical ) ); + report->fields[ report->field_count ].size = ( uint8_t )field->size; + memcpy( &report->fields[ report->field_count ].unit, &field->unit, sizeof( field->unit ) ); + report->fields[ report->field_count ].unit_exponent = field->unit_exponent; + if ( ( uint16_t )field->usage->page == LIBUSB_HID_USAGE_PAGE_USAGE_PAGE ) { + memcpy( &report->fields[ report->field_count ].usage, &field->usage[ -1 ], sizeof( uint32_t ) ); + if ( + field->usage->desktop == field->usage[ -1 ].desktop + || ! report->fields[ report->field_count ].attribute.variable + ) { + field->usage -= 2; + } else { + field->usage[ -1 ].desktop++; + } + } else { + memcpy( &report->fields[ report->field_count ].usage, field->usage--, sizeof( uint32_t ) ); + } + if (report->fields[ report->field_count ].attribute.variable ) { + field->count--; + report->report_length += report->fields[ report->field_count ].size; + report->fields[ report->field_count ].value.u32 = 0; + } else { + field->count = 0; + report->report_length += ( uint8_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count ); + report->fields[ report->field_count ].value.ptr = malloc( + ( size_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count / 8 ) ); + } + report->field_count++; + } + // set field usage 1 to 0 + constexpr uint32_t val = 0; + memcpy( &field->usage[ 1 ], &val, sizeof( uint32_t ) ); +} + +/** + * @fn void hid_enumerate_action_add_field(void*, libusb_hid_report_tag_t, uint32_t ) + * @brief Method to enumerate action add fields + * @param data + * @param tag + * @param value + */ +void hid_enumerate_action_add_field( + void* data, + const libusb_hid_report_tag_t tag, + const uint32_t value +) { + auto hid_field_t* field = ( hid_field_t* )data; + + switch ( tag ) { + case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: + hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); + break; + case LIBUSB_HID_REPORT_TAG_MAIN_COLLECTION: + uint32_t val; + memcpy( &val, field->usage, sizeof( uint32_t ) ); + if ( 0xffffffff == val ) { + field->usage++; + } + switch ( ( libusb_hid_main_collection_t )value ) { + case LIBUSB_HID_MAIN_COLLECTION_APPLICATION: + memcpy( &field->result->application, field->usage, sizeof( uint32_t ) ); + break; + case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: + memcpy( &field->physical, field->usage, sizeof( uint32_t ) ); + break; + default: + break; + } + break; + case LIBUSB_HID_REPORT_TAG_MAIN_END_COLLECTION: + switch ( ( libusb_hid_main_collection_t )value ) { + case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: + memset( &field->physical, 0, sizeof( uint32_t ) ); + break; + default: + break; + } + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_USAGE_PAGE: + field->page = ( libusb_hid_usage_page_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MINIMUM: + field->logical_minimum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MAXIMUM: + field->logical_maximum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MINIMUM: + field->physical_minimum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MAXIMUM: + field->physical_maximum = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT_EXPONENT: + field->unit_exponent = ( int32_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT: + memcpy( &field->unit, &value, sizeof( uint32_t ) ); + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_SIZE: + field->size = value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: + field->report = ( uint8_t )value; + break; + case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: + field->count = value; + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE: + field->usage++; + if ( value & 0xffff0000 ) { + memcpy( &field->usage, &value, sizeof( uint32_t ) ); + } else { + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = field->page; + } + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MINIMUM: + field->usage++; + if ( value & 0xffff0000 ) { + memcpy( &field->usage, &value, sizeof( uint32_t ) ); + } else { + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = field->page; + } + break; + case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MAXIMUM: + field->usage++; + field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; + field->usage->page = LIBUSB_HID_USAGE_PAGE_USAGE_PAGE; + break; + default: + break; + } +} + +/** + * @fn void hid_enumerate_report(void*, const size_t, hid_report_action_t, void*) + * @brief Method to enumerate report with callback + * @param descriptor + * @param length + * @param action + * @param data + */ +void hid_enumerate_report( + void* descriptor, + const size_t length, + const hid_report_action_t action, + void* data +) { + auto libusb_hid_report_item_t* item = ( libusb_hid_report_item_t* )descriptor; + libusb_hid_report_item_t* current = NULL; + size_t parsed_length = 0; + size_t current_index; + size_t current_length; + uint32_t value; + libusb_hid_report_tag_t tag; + + while ( parsed_length < length ) { + if ( ! current ) { + current = item; + current_index = 0; + current_length = 1 << ( current->size - 1 ); + value = 0; + tag = current->tag; + if ( current_length == 0 ) { + current = NULL; + } + } else { + if ( current->tag == LIBUSB_HID_REPORT_TAG_LONG && current_index < 2 ) { + if ( current_index == 0 ) { + current_length += *(uint8_t*)item; + } else { + tag |= ( uint16_t )*( uint8_t*)item << 8; + } + } else { + value |= ( uint32_t )( *( uint8_t* )item << ( 8 * current_index ) ); + } + if ( ++current_index == current_length ) { + current = NULL; + } + } + + if ( ! current ) { + if ( ( tag & 0x3 ) == 0x1 ) { + if ( current_length == 1 && ( value & 0x80 ) ) { + value |= 0xffffff00; + } else if ( current_length == 2 && ( value & 0x8000 ) ) { + value |= 0xffff0000; + } + } + action( data, tag, value ); + } + + item++; + parsed_length++; + } +} + +/** + * @fn int hid_parse_report_descriptor(libusb_hid_device_t*, void*, size_t) + * @brief Method to parse report descriptor + * @param device + * @param descriptor + * @param length + * @return + */ +int hid_parse_report_descriptor( + libusb_hid_device_t* device, + void* descriptor, + const size_t length +) { + hid_report_action_count_t header = { + .count = 0, + .indent = 0, + .input = false, + .output = false, + .feature = false, + }; + hid_report_field_t* report_field = NULL; + hid_field_t* field = NULL; + + // enumerate action count + hid_enumerate_report( descriptor, length, hid_enumerate_action_count_report, &header ); + STARTUP_PRINT( "Found %"PRIu8" reports!\r\n", header.count ) + // allocate space + libusb_hid_parser_result_t* result = malloc( + sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); + if ( ! result ) { + STARTUP_PRINT( "Unable to allocate memory for parser result\r\n" ) + return ENOMEM; + } + // clear out + memset( result, 0, sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); + // allocate space for report field + report_field = malloc( sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); + if ( ! report_field ) { + STARTUP_PRINT( "Unable to allocate memory for report field\r\n" ) + free( result ); + return ENOMEM; + } + // clear out + memset( report_field, 0, sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); + // prepare data + result->report_count = header.count; + + // enumerate report fields + hid_enumerate_report( descriptor, length, hid_enumerate_action_count_field, report_field ); + for ( size_t idx = 0; idx < header.count; idx++ ) { + // allocate space for report + result->report[ idx ] = malloc( + sizeof( libusb_hid_parser_report_t ) + sizeof( libusb_hid_parser_fields_t ) * report_field->data[ idx ].field_count ); + // handle error + if ( ! result->report[ idx ] ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + // free report field and result + free( report_field ); + free( result ); + return ENOMEM; + } + // fill report + result->report[ idx ]->index = ( uint8_t )idx; + result->report[ idx ]->field_count = 0; + result->report[ idx ]->id = report_field->data[ idx ].report_id; + result->report[ idx ]->type = report_field->data[ idx ].report_type; + result->report[ idx ]->report_length = 0; + result->report[ idx ]->report_buffer = NULL; + } + // free again report fields + free( report_field ); + + // allocate space for field + field = malloc( sizeof( hid_field_t ) ); + if ( ! field ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + free( result ); + return ENOMEM; + } + // clear out + memset( field, 0, sizeof( hid_field_t ) ); + // set fields usage + field->usage = calloc(16, sizeof( libusb_hid_full_usage_t* ) ); + if ( ! field->usage ) { + STARTUP_PRINT( "Unable to allocate space for report\r\n" ) + // free possible reports + for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { + if ( result->report[ free_idx ] ) { + free( result->report[ free_idx ] ); + } + } + free( field ); + free( result ); + return ENOMEM; + } + // populate field + constexpr uint32_t val = 0xffffffff; + memcpy( field->usage, &val, sizeof( libusb_hid_full_usage_t ) ); + field->result = result; + // cache usage field + void* usage = field->usage; + // enumerate fields + hid_enumerate_report( descriptor, length, hid_enumerate_action_add_field, field ); + + // populate result to device + device->parser_result = result; + + // free usage field and field again + free( usage ); + free( field ); + + // return success + return 0; +} + /** * @fn void hid_append(libusb_hid_device_t*) * @brief Append hid to handled devices diff --git a/bolthur/server/usb/device/hid/hid/hid.h b/bolthur/server/usb/device/hid/hid/hid.h index 813c6669..ec528faf 100644 --- a/bolthur/server/usb/device/hid/hid/hid.h +++ b/bolthur/server/usb/device/hid/hid/hid.h @@ -63,6 +63,14 @@ typedef struct { typedef void( *hid_report_action_t )( void* data, libusb_hid_report_tag_t tag, uint32_t value ); void hid_destroy_device( libusb_hid_device_t* ); +int hid_set_protocol( uint32_t, uint16_t, uint8_t ); +void hid_enumerate_action_count_report( void*, libusb_hid_report_tag_t, uint32_t ); +void hid_enumerate_action_count_field_process( hid_report_field_t*, uint32_t, libusb_hid_report_type_t ); +void hid_enumerate_action_count_field( void*, libusb_hid_report_tag_t, uint32_t ); +void hid_enumerate_action_add_field_process( hid_field_t*, uint32_t, libusb_hid_report_type_t ); +void hid_enumerate_action_add_field( void* data, libusb_hid_report_tag_t, uint32_t ); +void hid_enumerate_report( void*, size_t, hid_report_action_t, void* ); +int hid_parse_report_descriptor( libusb_hid_device_t*, void*, size_t ); void hid_append( libusb_hid_device_t* ); #endif diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c index b9123775..0b270817 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -29,542 +29,6 @@ #include "../../../../../../libusbd.h" #include "../../../../../../../library/usb/usb.h" -/** - * @fn int hid_set_protocol(uint32_t, uint16_t, uint8_t) - * @brief Set hid protocol - * @param device_number - * @param interface - * @param protocol - * @return - */ -static int hid_set_protocol( - const uint32_t device_number, - const uint16_t interface, - const uint8_t protocol -) { - uint32_t last_transfer; - libusb_transfer_error_t error; - // perform control message - const int result = usb_control_message( - device_number, - LIBUSB_TRANSFER_CONTROL, - LIBUSB_DIRECTION_OUT, - NULL, - 0, - &( libusb_device_request_t ){ - .request = LIBUSB_DEVICE_REQUEST_SET_PROTOCOL, - .type = 0x21, - .index = interface, - .value = protocol, - .length = 0, - }, - 10, /// FIXME: REPLACE WITH CONSTANT - &error, - &last_transfer - ); - // handle error - if ( 0 != result ) { - return result; - } - // handle error - if ( error != LIBUSB_TRANSFER_ERROR_NO_ERROR ) { - return EIO; - } - // return success - return 0; -} - -/** - * @fn void hid_enumerate_action_count_report(void*, libusb_hid_report_tag_t, uint32_t) - * @brief Method to enumerate action count report - * @param data - * @param tag - * @param value - */ -static void hid_enumerate_action_count_report( - void* data, - const libusb_hid_report_tag_t tag, - [[maybe_unused]] uint32_t value -) { - auto hid_report_action_count_t* report = ( hid_report_action_count_t* )data; - // handle tag - switch ( tag ) { - case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: - if ( !report->input ) { - report->count++; - report->input = true; - } - break; - case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: - if ( !report->output ) { - report->count++; - report->output = true; - } - break; - case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: - if ( !report->feature ) { - report->count++; - report->feature = true; - } - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: - report->input = report->output = report->feature = false; - default: - break; - } -} - -/** - * @fn void hid_enumerate_action_count_field_process(hid_report_field_t*, uint32_t, libusb_hid_report_type_t) - * @brief Wrapper to enumerate action count field - * @param field - * @param value - * @param type - */ -static void hid_enumerate_action_count_field_process( - hid_report_field_t* field, - uint32_t value, - const libusb_hid_report_type_t type -) { - hid_report_field_data_t* field_data = NULL; - for ( size_t idx = 0; idx < field->current; idx++ ) { - if ( - field->data[ idx ].report_id == field->report - && field->data[ idx ].report_type == type - ) { - field_data = &field->data[ idx ]; - break; - } - } - if ( ! field_data ) { - field_data = &field->data[ field->current++ ]; - field_data->report_id = field->report; - field_data->field_count = 0; - field_data->report_type = type; - } - void* v = &value; - if ( ( ( libusb_hid_main_item_t* )v )->variable ) { - field_data->field_count += ( uint8_t )field->count; - } else { - field_data->field_count++; - } -} - -/** - * @fn void hid_enumerate_action_count_field(void*, libusb_hid_report_tag_t, uint32_t) - * @brief Method to enumerate action count fields - * @param data - * @param tag - * @param value - */ -static void hid_enumerate_action_count_field( - void* data, - const libusb_hid_report_tag_t tag, - const uint32_t value -) { - auto hid_report_field_t* field = ( hid_report_field_t* )data; - switch ( tag ) { - case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: - hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); - break; - case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: - hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); - break; - case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: - hid_enumerate_action_count_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: - field->count = value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: - field->report = ( uint8_t )value; - break; - default: - break; - } -} - -/** - * @fn void hid_enumerate_action_add_field_process(hid_field_t*, uint32_t, libusb_hid_report_type_t) - * @brief Wrapper to process enumerate action add field - * @param field - * @param value - * @param type - */ -static void hid_enumerate_action_add_field_process( - hid_field_t* field, - const uint32_t value, - const libusb_hid_report_type_t type -) { - // try to find report from result - libusb_hid_parser_report_t* report = NULL; - for ( uint32_t idx = 0; idx < field->result->report_count; idx++ ) { - EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->id = %"PRIu8"\r\n", - idx, field->result->report[ idx ]->id ) - EARLY_STARTUP_PRINT( "field->result->report[ %"PRIu32" ]->type = %d\r\n", - idx, field->result->report[ idx ]->type ) - if ( - field->result->report[ idx ]->id == field->report - && field->result->report[ idx ]->type == type - ) { - report = field->result->report[ idx ]; - break; - } - } - // handle no report found - if ( ! report ) { - STARTUP_PRINT( "Report not found for %"PRIu8" / %d\r\n", - field->report, type ) - return; - } - // loop while field count is greater than 0 - while ( field->count > 0 ) { - // extract val - uint32_t val; - memcpy( &val, field->usage, sizeof( val ) ); - // handle first iteration - if ( val == 0xffffffff ) { - field->usage++; - } - memcpy( &report->fields[ report->field_count ].attribute, &value, sizeof( uint32_t ) ); - report->fields[ report->field_count ].count = ( uint8_t)( report->fields[ report->field_count ].attribute.variable ? 1 : field->count ); - report->fields[ report->field_count ].logical_maximum = field->logical_maximum; - report->fields[ report->field_count ].logical_minimum = field->logical_minimum; - report->fields[ report->field_count ].offset = report->report_length; - report->fields[ report->field_count ].physical_maximum = field->physical_maximum; - report->fields[ report->field_count ].physical_minimum = field->physical_minimum; - memcpy( &report->fields[ report->field_count ].physical_usage, &field->physical, sizeof( field->physical ) ); - report->fields[ report->field_count ].size = ( uint8_t )field->size; - memcpy( &report->fields[ report->field_count ].unit, &field->unit, sizeof( field->unit ) ); - report->fields[ report->field_count ].unit_exponent = field->unit_exponent; - if ( ( uint16_t )field->usage->page == LIBUSB_HID_USAGE_PAGE_USAGE_PAGE ) { - memcpy( &report->fields[ report->field_count ].usage, &field->usage[ -1 ], sizeof( uint32_t ) ); - if ( - field->usage->desktop == field->usage[ -1 ].desktop - || ! report->fields[ report->field_count ].attribute.variable - ) { - field->usage -= 2; - } else { - field->usage[ -1 ].desktop++; - } - } else { - memcpy( &report->fields[ report->field_count ].usage, field->usage--, sizeof( uint32_t ) ); - } - if (report->fields[ report->field_count ].attribute.variable ) { - field->count--; - report->report_length += report->fields[ report->field_count ].size; - report->fields[ report->field_count ].value.u32 = 0; - } else { - field->count = 0; - report->report_length += ( uint8_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count ); - report->fields[ report->field_count ].value.ptr = malloc( - ( size_t )( report->fields[ report->field_count ].size * report->fields[ report->field_count ].count / 8 ) ); - } - report->field_count++; - } - // set field usage 1 to 0 - constexpr uint32_t val = 0; - memcpy( &field->usage[ 1 ], &val, sizeof( uint32_t ) ); -} - -/** - * @fn void hid_enumerate_action_add_field(void*, libusb_hid_report_tag_t, uint32_t ) - * @brief Method to enumerate action add fields - * @param data - * @param tag - * @param value - */ -static void hid_enumerate_action_add_field( - void* data, - const libusb_hid_report_tag_t tag, - const uint32_t value -) { - auto hid_field_t* field = ( hid_field_t* )data; - - switch ( tag ) { - case LIBUSB_HID_REPORT_TAG_MAIN_FEATURE: - hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_FEATURE ); - break; - case LIBUSB_HID_REPORT_TAG_MAIN_OUTPUT: - hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_OUTPUT ); - break; - case LIBUSB_HID_REPORT_TAG_MAIN_INPUT: - hid_enumerate_action_add_field_process( field, value, LIBUSB_HID_REPORT_TYPE_INPUT ); - break; - case LIBUSB_HID_REPORT_TAG_MAIN_COLLECTION: - uint32_t val; - memcpy( &val, field->usage, sizeof( uint32_t ) ); - if ( 0xffffffff == val ) { - field->usage++; - } - switch ( ( libusb_hid_main_collection_t )value ) { - case LIBUSB_HID_MAIN_COLLECTION_APPLICATION: - memcpy( &field->result->application, field->usage, sizeof( uint32_t ) ); - break; - case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: - memcpy( &field->physical, field->usage, sizeof( uint32_t ) ); - break; - default: - break; - } - break; - case LIBUSB_HID_REPORT_TAG_MAIN_END_COLLECTION: - switch ( ( libusb_hid_main_collection_t )value ) { - case LIBUSB_HID_MAIN_COLLECTION_PHYSICAL: - memset( &field->physical, 0, sizeof( uint32_t ) ); - break; - default: - break; - } - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_USAGE_PAGE: - field->page = ( libusb_hid_usage_page_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MINIMUM: - field->logical_minimum = ( int32_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_LOGICAL_MAXIMUM: - field->logical_maximum = ( int32_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MINIMUM: - field->physical_minimum = ( int32_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_PHYSICAL_MAXIMUM: - field->physical_maximum = ( int32_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT_EXPONENT: - field->unit_exponent = ( int32_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_UNIT: - memcpy( &field->unit, &value, sizeof( uint32_t ) ); - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_SIZE: - field->size = value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_ID: - field->report = ( uint8_t )value; - break; - case LIBUSB_HID_REPORT_TAG_GLOBAL_REPORT_COUNT: - field->count = value; - break; - case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE: - field->usage++; - if ( value & 0xffff0000 ) { - memcpy( &field->usage, &value, sizeof( uint32_t ) ); - } else { - field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; - field->usage->page = field->page; - } - break; - case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MINIMUM: - field->usage++; - if ( value & 0xffff0000 ) { - memcpy( &field->usage, &value, sizeof( uint32_t ) ); - } else { - field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; - field->usage->page = field->page; - } - break; - case LIBUSB_HID_REPORT_TAG_LOCAL_USAGE_MAXIMUM: - field->usage++; - field->usage->desktop = ( libusb_hid_usage_page_desktop_t )value; - field->usage->page = LIBUSB_HID_USAGE_PAGE_USAGE_PAGE; - break; - default: - break; - } -} - -/** - * @fn void hid_enumerate_report(void*, const size_t, hid_report_action_t, void*) - * @brief Method to enumerate report with callback - * @param descriptor - * @param length - * @param action - * @param data - */ -static void hid_enumerate_report( - void* descriptor, - const size_t length, - const hid_report_action_t action, - void* data -) { - auto libusb_hid_report_item_t* item = ( libusb_hid_report_item_t* )descriptor; - libusb_hid_report_item_t* current = NULL; - size_t parsed_length = 0; - size_t current_index; - size_t current_length; - uint32_t value; - libusb_hid_report_tag_t tag; - - while ( parsed_length < length ) { - if ( ! current ) { - current = item; - current_index = 0; - current_length = 1 << ( current->size - 1 ); - value = 0; - tag = current->tag; - if ( current_length == 0 ) { - current = NULL; - } - } else { - if ( current->tag == LIBUSB_HID_REPORT_TAG_LONG && current_index < 2 ) { - if ( current_index == 0 ) { - current_length += *(uint8_t*)item; - } else { - tag |= ( uint16_t )*( uint8_t*)item << 8; - } - } else { - value |= ( uint32_t )( *( uint8_t* )item << ( 8 * current_index ) ); - } - if ( ++current_index == current_length ) { - current = NULL; - } - } - - if ( ! current ) { - if ( ( tag & 0x3 ) == 0x1 ) { - if ( current_length == 1 && ( value & 0x80 ) ) { - value |= 0xffffff00; - } else if ( current_length == 2 && ( value & 0x8000 ) ) { - value |= 0xffff0000; - } - } - action( data, tag, value ); - } - - item++; - parsed_length++; - } -} - -/** - * @fn int hid_parse_report_descriptor(libusb_hid_device_t*, void*, size_t) - * @brief Method to parse report descriptor - * @param device - * @param descriptor - * @param length - * @return - */ -static int hid_parse_report_descriptor( - libusb_hid_device_t* device, - void* descriptor, - const size_t length -) { - hid_report_action_count_t header = { - .count = 0, - .indent = 0, - .input = false, - .output = false, - .feature = false, - }; - hid_report_field_t* report_field = NULL; - hid_field_t* field = NULL; - - // enumerate action count - hid_enumerate_report( descriptor, length, hid_enumerate_action_count_report, &header ); - STARTUP_PRINT( "Found %"PRIu8" reports!\r\n", header.count ) - // allocate space - libusb_hid_parser_result_t* result = malloc( - sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); - if ( ! result ) { - STARTUP_PRINT( "Unable to allocate memory for parser result\r\n" ) - return ENOMEM; - } - // clear out - memset( result, 0, sizeof( libusb_hid_parser_result_t ) + sizeof( libusb_hid_parser_report_t* ) * header.count ); - // allocate space for report field - report_field = malloc( sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); - if ( ! report_field ) { - STARTUP_PRINT( "Unable to allocate memory for report field\r\n" ) - free( result ); - return ENOMEM; - } - // clear out - memset( report_field, 0, sizeof( hid_report_field_t ) + sizeof( hid_report_field_data_t ) * header.count ); - // prepare data - result->report_count = header.count; - - // enumerate report fields - hid_enumerate_report( descriptor, length, hid_enumerate_action_count_field, report_field ); - for ( size_t idx = 0; idx < header.count; idx++ ) { - // allocate space for report - result->report[ idx ] = malloc( - sizeof( libusb_hid_parser_report_t ) + sizeof( libusb_hid_parser_fields_t ) * report_field->data[ idx ].field_count ); - // handle error - if ( ! result->report[ idx ] ) { - STARTUP_PRINT( "Unable to allocate space for report\r\n" ) - // free possible reports - for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { - if ( result->report[ free_idx ] ) { - free( result->report[ free_idx ] ); - } - } - // free report field and result - free( report_field ); - free( result ); - return ENOMEM; - } - // fill report - result->report[ idx ]->index = ( uint8_t )idx; - result->report[ idx ]->field_count = 0; - result->report[ idx ]->id = report_field->data[ idx ].report_id; - result->report[ idx ]->type = report_field->data[ idx ].report_type; - result->report[ idx ]->report_length = 0; - result->report[ idx ]->report_buffer = NULL; - } - // free again report fields - free( report_field ); - - // allocate space for field - field = malloc( sizeof( hid_field_t ) ); - if ( ! field ) { - STARTUP_PRINT( "Unable to allocate space for report\r\n" ) - // free possible reports - for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { - if ( result->report[ free_idx ] ) { - free( result->report[ free_idx ] ); - } - } - free( result ); - return ENOMEM; - } - // clear out - memset( field, 0, sizeof( hid_field_t ) ); - // set fields usage - field->usage = calloc(16, sizeof( libusb_hid_full_usage_t* ) ); - if ( ! field->usage ) { - STARTUP_PRINT( "Unable to allocate space for report\r\n" ) - // free possible reports - for ( size_t free_idx = 0; free_idx < header.count; free_idx++ ) { - if ( result->report[ free_idx ] ) { - free( result->report[ free_idx ] ); - } - } - free( field ); - free( result ); - return ENOMEM; - } - // populate field - constexpr uint32_t val = 0xffffffff; - memcpy( field->usage, &val, sizeof( libusb_hid_full_usage_t ) ); - field->result = result; - // cache usage field - void* usage = field->usage; - // enumerate fields - hid_enumerate_report( descriptor, length, hid_enumerate_action_add_field, field ); - - // populate result to device - device->parser_result = result; - - // free usage field and field again - free( usage ); - free( field ); - - // return success - return 0; -} - /** * @fn void rpc_hid_attach(size_t, pid_t, size_t, size_t) * @brief Register rpc handler attach diff --git a/bolthur/server/usb/device/hub/hub.c b/bolthur/server/usb/device/hub/hub.c index a3db2ca7..d987a67a 100644 --- a/bolthur/server/usb/device/hub/hub.c +++ b/bolthur/server/usb/device/hub/hub.c @@ -17,11 +17,46 @@ * along with bolthur/kernel. If not, see . */ +#include +#include +#include #include "hub.h" #include "../../../libusb.h" +#include "../../../../library/usb/usb.h" libusb_hub_device_t* hub_head = NULL; +/** + * @fn void custom_nanosleep(const struct timespec*) + * @brief Custom nanosleep implementation + * @param rqtp + */ +static void custom_nanosleep( const struct timespec* rqtp ) { + if ( 0 > rqtp->tv_nsec ) { + errno = EINVAL; + return; + } + // get clock frequency + size_t frequency = _syscall_timer_frequency(); + // calculate second timeout + size_t timeout = ( size_t )( rqtp->tv_sec * frequency ); + size_t tick; + // add nanosecond offset + timeout += ( size_t )( ( double )rqtp->tv_nsec * ( double )frequency / 1000000000.0 ); + // add tick count to get an end time + timeout += _syscall_timer_tick_count(); + // loop until timeout is reached + while ( ( tick = _syscall_timer_tick_count() ) < timeout ) { + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif + __asm__ __volatile__( "nop" ); + } + //#if defined( RPC_ENABLE_DEBUG ) + // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) + //#endif +} + /** * @fn void hub_append(libusb_hub_device_t*) * @brief Append hub to handled list @@ -46,3 +81,587 @@ void hub_append( libusb_hub_device_t* hub ) { found->next = hub; hub->prev = found; } + +/** + * @fn int hub_read_descriptor(uint32_t, void**) + * @brief Read up descriptor + * @param device_number + * @param descriptor + * @return + */ +int hub_read_descriptor( const uint32_t device_number, void** descriptor ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Reading usb hub descriptor\r\n" ) + #endif + // space for buffer on stack + libusb_descriptor_header_t header; + // get hub descriptor + int result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, + &header, sizeof( header ), sizeof( header ), 0x20 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get hub descriptor header: %s\r\n", + strerror( result ) ); + #endif + // return result + return result; + } + // allocate space in driver data + if ( ! *descriptor ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Allocating memory for hub descriptor\r\n" ); + #endif + // allocate memory + *descriptor = malloc( header.descriptor_length ); + // handle error + if ( ! *descriptor ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate memory for hub descriptor\r\n" ); + #endif + // return nomem + return ENOMEM; + } + } + // read descriptor itself + result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, + *descriptor, header.descriptor_length, header.descriptor_length, 0x20 ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get hub descriptor: %s\r\n", strerror( result ) ); + #endif + // return result + return result; + } + // return success + return 0; +} + +/** + * @fn int hub_get_status(uint32_t, libusb_hub_device_t*) + * @brief Function to get hub status + * @param device_number + * @param hub_device + * @return + */ +int hub_get_status( + const uint32_t device_number, + libusb_hub_device_t* hub_device +) { + // space for last transfer and error + uint32_t last_transfer; + libusb_transfer_error_t error; + // perform control message + const int result = usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_IN, + &hub_device->status, + sizeof( libusb_hub_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa0, + .length = sizeof( libusb_hub_full_status_t ), + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to get host status: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // handle not enough read + if ( last_transfer != sizeof( libusb_hub_full_status_t ) ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to read hub status for %s\r\n", usb_get_description( device_number ) ) + #endif + // return error + return EIO; + } + // return success + return 0; +} + +/** + * @fn int hub_change_port_feature(uint32_t, libusb_hub_port_feature_t, uint8_t, bool) + * @brief Method to change port feature + * @param device_number + * @param feature + * @param port + * @param set + * @return + */ +int hub_change_port_feature( + const uint32_t device_number, + const libusb_hub_port_feature_t feature, + const uint8_t port, + const bool set +) { + uint32_t last_transfer; + libusb_transfer_error_t error; + return usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_OUT, + NULL, + 0, + &( libusb_device_request_t ) { + .request = set + ? LIBUSB_DEVICE_REQUEST_SET_FEATURE + : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, + .type = 0x23, + .value = ( uint16_t )feature, + .index = port + 1, + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); +} + +/** + * @fn int hub_power_on(uint32_t, libusb_hub_device_t*) + * @brief Function to power on hub + * @param device_number + * @param hub_device + * @return + */ +int hub_power_on( + const uint32_t device_number, + const libusb_hub_device_t* hub_device +) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Powering up %s\r\n", usb_get_description( device_number ) ) + #endif + // loop through all children and power on the port + for ( uint32_t child = 0; child < hub_device->max_children; child++ ) { + #if defined( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Power up port %"PRIu32" of %s\r\n", child, usb_get_description( device_number ) ) + #endif + // try to change port feature + [[maybe_unused]] const int result = hub_change_port_feature( + device_number, + LIBUSB_HUB_PORT_FEATURE_POWER, + ( uint8_t )child, + true + ); + // handle error + if ( 0 != result ) { + // debug output only + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on port %"PRIu32" of %s: %s\r\n", + child, usb_get_description( device_number ), strerror( result ) ) + #endif + } + } + // milliseconds to sleep + const long milliseconds = hub_device->descriptor->power_good_delay * 2; + STARTUP_PRINT( "sleeping %ld milliseconds\r\n", milliseconds ) + // sleep a bit + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + // return success + return 0; +} + +/** + * @fn int hub_get_port_status(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Function to get port status of hub + * @param device_number + * @param hub + * @param port + * @return + */ +int hub_get_port_status( + const uint32_t device_number, + libusb_hub_device_t* hub, + const uint8_t port +) { + uint32_t last_transfer; + libusb_transfer_error_t error; + const int result = usb_control_message( + device_number, + LIBUSB_TRANSFER_CONTROL, + LIBUSB_DIRECTION_IN, + &hub->port_status[ port ], + sizeof( libusb_hub_port_full_status_t ), + &( libusb_device_request_t ){ + .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, + .type = 0xa3, + .index = port + 1, + .length = sizeof( libusb_hub_port_full_status_t ), + }, + 10, /// FIXME: REPLACE WITH CONSTANT + &error, + &last_transfer + ); + // handle result wrong + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Fetching port status failed\r\n" ) + #endif + // return result + return result; + } + // handle wrong size + if ( last_transfer != sizeof( libusb_hub_port_full_status_t ) ) { + // debug output + #if defined( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to read port %"PRIu8" status for %s. Received %"PRIu32" but expected %d\r\n", + port, usb_get_description( device_number ), last_transfer, sizeof( libusb_hub_port_full_status_t ) ) + #endif + // return io error + return EIO; + } + // return success + return 0; +} + +/** + * @fn int hub_port_reset(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Method to reset hub port + * @param device_number + * @param device_data + * @param port + * @return + */ +int hub_port_reset( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const uint8_t port +) { + // cache status + const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; + uint32_t retry; + int result; + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Resetting port %"PRIu8" of device %s\r\n", port, usb_get_description( device_number ) ) + #endif + // retry three times + for ( retry = 0; retry < 3; retry++ ) { + // try to reset + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET, port, true ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to reset port %"PRIu8" of device %s\r\n", + port, usb_get_description( device_number ) ) + #endif + // return result + return result; + } + // initialize timeout + uint32_t timeout = 0; + do { + // delay 20 milliseconds + const long milliseconds = 20; + custom_nanosleep( &(struct timespec){ + .tv_sec = milliseconds / 1000, + .tv_nsec = ( milliseconds % 1000 ) * 1000000, + } ); + // read port data + result = hub_get_port_status( device_number, device_data, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status of port %"PRIu8" from %s\r\n", + port, usb_get_description( device_number ) ) + #endif + // return result + return result; + } + timeout++; + } while ( ! full_status->change.reset_changed && ! full_status->status.enabled && timeout < 10 ); + // handle timeout reached + if ( timeout >= 10 ) { + continue; + } + + if ( full_status->change.connected_changed || ! full_status->status.connected ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "connected_changed = %d, connected = %d\r\n", + full_status->change.connected_changed, full_status->status.connected ) + #endif + // return error + return ENXIO; + } + + // handle enabled + if ( full_status->status.enabled ) { + break; + } + } + // handle retry reached + if ( 3 == retry ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Cannot enable port %"PRIu8" on %s\r\n", + port, usb_get_description( device_number ) ) + #endif + // return error + return EIO; + } + // clear reset + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to clear port %"PRIu8" reset of %s\r\n", + port, usb_get_description( device_number ) ) + #endif + // return result + return result; + } + // return success + return 0; +} + +/** + * @fn int hub_port_connection_changed(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Method to handle connection change of port + * @param device_number + * @param device_data + * @param port + * @return + */ +int hub_port_connection_changed( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const uint8_t port +) { + // cache status + const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; + // get hub port status + int result = hub_get_port_status( device_number, device_data, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status (2) for %s with port %"PRIu8"\r\n", + usb_get_description( device_number ), port + 1 ) + #endif + // return result + return result; + } + // change connection feature + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE, port, false ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear connection change on %s with port %"PRIu8"\r\n", + usb_get_description( device_number ), port + 1 ) + #endif + // return result + return result; + } + // handle not connected and not enabled + if ( ( ! full_status->status.connected && ! full_status->status.enabled ) || device_data->children[ port ] ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Disconnected %s with port %"PRIu8"\r\n", + usb_get_description( device_number ), port + 1 ) + #endif + /// FIXME: HANDLE! + } + // reset hub port + result = hub_port_reset( device_number, device_data, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Could not reset port %"PRIu8" of %s for new device\r\n", + port + 1, usb_get_description( device_number ) ) + #endif + // return result + return result; + } + // get hub port status + result = hub_get_port_status( device_number, device_data, port ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to get status (3) for %s with port %"PRIu8"\r\n", + usb_get_description( device_number ), port + 1 ) + #endif + // return result + return result; + } + libusb_speed_t speed = LIBUSB_SPEED_FULL; + if ( full_status->status.high_speed_attached ) { + speed = LIBUSB_SPEED_HIGH; + } else if ( full_status->status.low_speed_attached ) { + speed = LIBUSB_SPEED_LOW; + } + // attach new device + result = usb_attach_device( device_number, port, speed ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach device: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // return success + return 0; +} + +/** + * @fn int hub_check_connection(uint32_t, libusb_hub_device_t*, uint8_t) + * @brief Function to check hub connection + * @param device_number + * @param device_data + * @param port + * @return + */ +int hub_check_connection( + const uint32_t device_number, + libusb_hub_device_t* device_data, + const uint8_t port +) { + // cache hub device + const bool previously_connected = device_data->port_status[ port ].status.connected; + uint32_t roothub_device_number; + int result = usb_get_root_hub( &roothub_device_number ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to retrieve root hub: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // get port status + result = hub_get_port_status( device_number, device_data, port ); + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to retrieve port status: %s\r\n", strerror( result ) ) + #endif + // return result + return result; + } + // cache full status + libusb_hub_port_full_status_t* port_status = &device_data->port_status[ port ]; + // handle connected to root device + STARTUP_PRINT( "device_number = %"PRIu32" connected = %d, previously_connected = %d\r\n", + device_number, port_status->status.connected ? 1 : 0, previously_connected ? 1 : 0 ) + // handle directly connected to root hub + if ( + device_number == roothub_device_number + && port_status->status.connected != previously_connected + ) { + STARTUP_PRINT( "Root hub which is connected and was previously not or vice versa\r\n" ) + port_status->change.connected_changed = true; + } + // handle connection changed + if ( port_status->change.connected_changed ) { + STARTUP_PRINT( "Connected changed!\r\n" ) + hub_port_connection_changed( device_number, device_data, port ); + } + if ( port_status->change.enabled_changed ) { + STARTUP_PRINT( "ENABLED CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear enable change for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( device_number ) ) + #endif + } + + if ( ! port_status->status.enabled && port_status->status.connected && device_data->children[ port ] ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( + "%s. Port %d has been disabled but is connected. This can be caused by interference. Enabling it again\r\n", + usb_get_description( device_number ), port + 1 ) + #endif + // call connection changed + hub_port_connection_changed( device_number, device_data, port ); + } + } + if ( port_status->status.suspended ) { + STARTUP_PRINT( "SUSPENDED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_SUSPEND, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to suspend port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( device_number ) ) + #endif + } + } + if ( port_status->change.over_current_changed ) { + STARTUP_PRINT( "OVER CURRENT CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear over current for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( device_number ) ) + #endif + } + // power on hub + result = hub_power_on( device_number, device_data ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to power on device %s: %s\r\n", + usb_get_description( device_number ), strerror( result ) ) + #endif + } + } + if ( port_status->change.reset_changed ) { + STARTUP_PRINT( "RESET CHANGED!\r\n" ) + // clear enable change flag + result = hub_change_port_feature( + device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); + // handle error + if ( 0 != result ) { + // debug output + #if defined ( HUB_ENABLE_DEBUG ) + STARTUP_PRINT( "Failed to clear reset for port %"PRIu8" for %s\r\n", + port + 1, usb_get_description( device_number ) ) + #endif + } + } + // return success + return 0; +} diff --git a/bolthur/server/usb/device/hub/hub.h b/bolthur/server/usb/device/hub/hub.h index 5efbe584..ede5dac3 100644 --- a/bolthur/server/usb/device/hub/hub.h +++ b/bolthur/server/usb/device/hub/hub.h @@ -25,5 +25,13 @@ #define HUB_ENABLE_DEBUG 1 void hub_append( libusb_hub_device_t* ); +int hub_read_descriptor( uint32_t, void** ); +int hub_get_status( uint32_t, libusb_hub_device_t* ); +int hub_change_port_feature( uint32_t, libusb_hub_port_feature_t, uint8_t, bool ); +int hub_power_on( uint32_t, const libusb_hub_device_t* ); +int hub_get_port_status( uint32_t, libusb_hub_device_t*, uint8_t ); +int hub_port_reset( uint32_t, libusb_hub_device_t*, uint8_t ); +int hub_port_connection_changed( uint32_t, libusb_hub_device_t*, uint8_t ); +int hub_check_connection( uint32_t, libusb_hub_device_t*, uint8_t ); #endif diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index 5ddc0965..b261e035 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -28,621 +28,6 @@ #include "../../../../../libusbd.h" #include "../../../../../../library/usb/usb.h" -/** - * @fn void custom_nanosleep(const struct timespec*) - * @brief Custom nanosleep implementation - * @param rqtp - */ -static void custom_nanosleep( const struct timespec* rqtp ) { - if ( 0 > rqtp->tv_nsec ) { - errno = EINVAL; - return; - } - // get clock frequency - size_t frequency = _syscall_timer_frequency(); - // calculate second timeout - size_t timeout = ( size_t )( rqtp->tv_sec * frequency ); - size_t tick; - // add nanosecond offset - timeout += ( size_t )( ( double )rqtp->tv_nsec * ( double )frequency / 1000000000.0 ); - // add tick count to get an end time - timeout += _syscall_timer_tick_count(); - // loop until timeout is reached - while ( ( tick = _syscall_timer_tick_count() ) < timeout ) { - //#if defined( RPC_ENABLE_DEBUG ) - // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) - //#endif - __asm__ __volatile__( "nop" ); - } - //#if defined( RPC_ENABLE_DEBUG ) - // EARLY_STARTUP_PRINT( "sleeping %d / %d\r\n", tick, timeout ) - //#endif -} - -/** - * @fn int attach_hub_read_descriptor(uint32_t, void**) - * @brief Read up descriptor - * @param device_number - * @param descriptor - * @return - */ -static int attach_hub_read_descriptor( const uint32_t device_number, void** descriptor ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Reading usb hub descriptor\r\n" ) - #endif - // space for buffer on stack - libusb_descriptor_header_t header; - // get hub descriptor - int result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, - &header, sizeof( header ), sizeof( header ), 0x20 ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to get hub descriptor header: %s\r\n", - strerror( result ) ); - #endif - // return result - return result; - } - // allocate space in driver data - if ( ! *descriptor ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Allocating memory for hub descriptor\r\n" ); - #endif - // allocate memory - *descriptor = malloc( header.descriptor_length ); - // handle error - if ( ! *descriptor ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to allocate memory for hub descriptor\r\n" ); - #endif - // return nomem - return ENOMEM; - } - } - // read descriptor itself - result = usb_get_descriptor( device_number, LIBUSB_DESCRIPTOR_HUB, 0, 0, - *descriptor, header.descriptor_length, header.descriptor_length, 0x20 ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to get hub descriptor: %s\r\n", strerror( result ) ); - #endif - // return result - return result; - } - // return success - return 0; -} - -/** - * @fn int attach_hub_get_status(uint32_t, libusb_hub_device_t*) - * @brief Function to get hub status - * @param device_number - * @param hub_device - * @return - */ -static int attach_hub_get_status( - const uint32_t device_number, - libusb_hub_device_t* hub_device -) { - // space for last transfer and error - uint32_t last_transfer; - libusb_transfer_error_t error; - // perform control message - const int result = usb_control_message( - device_number, - LIBUSB_TRANSFER_CONTROL, - LIBUSB_DIRECTION_IN, - &hub_device->status, - sizeof( libusb_hub_full_status_t ), - &( libusb_device_request_t ){ - .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, - .type = 0xa0, - .length = sizeof( libusb_hub_full_status_t ), - }, - 10, /// FIXME: REPLACE WITH CONSTANT - &error, - &last_transfer - ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to get host status: %s\r\n", strerror( result ) ) - #endif - // return result - return result; - } - // handle not enough read - if ( last_transfer != sizeof( libusb_hub_full_status_t ) ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to read hub status for %s\r\n", usb_get_description( device_number ) ) - #endif - // return error - return EIO; - } - // return success - return 0; -} - -/** - * @fn int attach_hub_change_port_feature(uint32_t, libusb_hub_port_feature_t, uint8_t, bool) - * @brief Method to change port feature - * @param device_number - * @param feature - * @param port - * @param set - * @return - */ -static int attach_hub_change_port_feature( - const uint32_t device_number, - const libusb_hub_port_feature_t feature, - const uint8_t port, - const bool set -) { - uint32_t last_transfer; - libusb_transfer_error_t error; - return usb_control_message( - device_number, - LIBUSB_TRANSFER_CONTROL, - LIBUSB_DIRECTION_OUT, - NULL, - 0, - &( libusb_device_request_t ) { - .request = set - ? LIBUSB_DEVICE_REQUEST_SET_FEATURE - : LIBUSB_DEVICE_REQUEST_CLEAR_FEATURE, - .type = 0x23, - .value = ( uint16_t )feature, - .index = port + 1, - }, - 10, /// FIXME: REPLACE WITH CONSTANT - &error, - &last_transfer - ); -} - -/** - * @fn int attach_hub_power_on(uint32_t, libusb_hub_device_t*) - * @brief Function to power on hub - * @param device_number - * @param hub_device - * @return - */ -static int attach_hub_power_on( - const uint32_t device_number, - const libusb_hub_device_t* hub_device -) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Powering up %s\r\n", usb_get_description( device_number ) ) - #endif - // loop through all children and power on the port - for ( uint32_t child = 0; child < hub_device->max_children; child++ ) { - #if defined( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Power up port %"PRIu32" of %s\r\n", child, usb_get_description( device_number ) ) - #endif - // try to change port feature - [[maybe_unused]] const int result = attach_hub_change_port_feature( - device_number, - LIBUSB_HUB_PORT_FEATURE_POWER, - ( uint8_t )child, - true - ); - // handle error - if ( 0 != result ) { - // debug output only - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to power on port %"PRIu32" of %s: %s\r\n", - child, usb_get_description( device_number ), strerror( result ) ) - #endif - } - } - // milliseconds to sleep - const long milliseconds = hub_device->descriptor->power_good_delay * 2; - STARTUP_PRINT( "sleeping %ld milliseconds\r\n", milliseconds ) - // sleep a bit - custom_nanosleep( &(struct timespec){ - .tv_sec = milliseconds / 1000, - .tv_nsec = ( milliseconds % 1000 ) * 1000000, - } ); - // return success - return 0; -} - -/** - * @fn int attach_hub_get_port_status(uint32_t, libusb_hub_device_t*, uint8_t) - * @brief Function to get port status of hub - * @param device_number - * @param hub - * @param port - * @return - */ -static int attach_hub_get_port_status( - const uint32_t device_number, - libusb_hub_device_t* hub, - const uint8_t port -) { - uint32_t last_transfer; - libusb_transfer_error_t error; - const int result = usb_control_message( - device_number, - LIBUSB_TRANSFER_CONTROL, - LIBUSB_DIRECTION_IN, - &hub->port_status[ port ], - sizeof( libusb_hub_port_full_status_t ), - &( libusb_device_request_t ){ - .request = LIBUSB_DEVICE_REQUEST_GET_STATUS, - .type = 0xa3, - .index = port + 1, - .length = sizeof( libusb_hub_port_full_status_t ), - }, - 10, /// FIXME: REPLACE WITH CONSTANT - &error, - &last_transfer - ); - // handle result wrong - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Fetching port status failed\r\n" ) - #endif - // return result - return result; - } - // handle wrong size - if ( last_transfer != sizeof( libusb_hub_port_full_status_t ) ) { - // debug output - #if defined( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to read port %"PRIu8" status for %s. Received %"PRIu32" but expected %d\r\n", - port, usb_get_description( device_number ), last_transfer, sizeof( libusb_hub_port_full_status_t ) ) - #endif - // return io error - return EIO; - } - // return success - return 0; -} - -/** - * @fn int attach_hub_port_reset(uint32_t, libusb_hub_device_t*, uint8_t) - * @brief Method to reset hub port - * @param device_number - * @param device_data - * @param port - * @return - */ -static int attach_hub_port_reset( - const uint32_t device_number, - libusb_hub_device_t* device_data, - const uint8_t port -) { - // cache status - const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; - uint32_t retry; - int result; - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Resetting port %"PRIu8" of device %s\r\n", port, usb_get_description( device_number ) ) - #endif - // retry three times - for ( retry = 0; retry < 3; retry++ ) { - // try to reset - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_RESET, port, true ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to reset port %"PRIu8" of device %s\r\n", - port, usb_get_description( device_number ) ) - #endif - // return result - return result; - } - // initialize timeout - uint32_t timeout = 0; - do { - // delay 20 milliseconds - const long milliseconds = 20; - custom_nanosleep( &(struct timespec){ - .tv_sec = milliseconds / 1000, - .tv_nsec = ( milliseconds % 1000 ) * 1000000, - } ); - // read port data - result = attach_hub_get_port_status( device_number, device_data, port ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to get status of port %"PRIu8" from %s\r\n", - port, usb_get_description( device_number ) ) - #endif - // return result - return result; - } - timeout++; - } while ( ! full_status->change.reset_changed && ! full_status->status.enabled && timeout < 10 ); - // handle timeout reached - if ( timeout >= 10 ) { - continue; - } - - if ( full_status->change.connected_changed || ! full_status->status.connected ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "connected_changed = %d, connected = %d\r\n", - full_status->change.connected_changed, full_status->status.connected ) - #endif - // return error - return ENXIO; - } - - // handle enabled - if ( full_status->status.enabled ) { - break; - } - } - // handle retry reached - if ( 3 == retry ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Cannot enable port %"PRIu8" on %s\r\n", - port, usb_get_description( device_number ) ) - #endif - // return error - return EIO; - } - // clear reset - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to clear port %"PRIu8" reset of %s\r\n", - port, usb_get_description( device_number ) ) - #endif - // return result - return result; - } - // return success - return 0; -} - -/** - * @fn int attach_hub_port_connection_changed(uint32_t, libusb_hub_device_t*, uint8_t) - * @brief Method to handle connection change of port - * @param device_number - * @param device_data - * @param port - * @return - */ -static int attach_hub_port_connection_changed( - const uint32_t device_number, - libusb_hub_device_t* device_data, - const uint8_t port -) { - // cache status - const libusb_hub_port_full_status_t* full_status = &device_data->port_status[ port ]; - // get hub port status - int result = attach_hub_get_port_status( device_number, device_data, port ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to get status (2) for %s with port %"PRIu8"\r\n", - usb_get_description( device_number ), port + 1 ) - #endif - // return result - return result; - } - // change connection feature - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_CONNECTION_CHANGE, port, false ); - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to clear connection change on %s with port %"PRIu8"\r\n", - usb_get_description( device_number ), port + 1 ) - #endif - // return result - return result; - } - // handle not connected and not enabled - if ( ( ! full_status->status.connected && ! full_status->status.enabled ) || device_data->children[ port ] ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Disconnected %s with port %"PRIu8"\r\n", - usb_get_description( device_number ), port + 1 ) - #endif - /// FIXME: HANDLE! - } - // reset hub port - result = attach_hub_port_reset( device_number, device_data, port ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Could not reset port %"PRIu8" of %s for new device\r\n", - port + 1, usb_get_description( device_number ) ) - #endif - // return result - return result; - } - // get hub port status - result = attach_hub_get_port_status( device_number, device_data, port ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to get status (3) for %s with port %"PRIu8"\r\n", - usb_get_description( device_number ), port + 1 ) - #endif - // return result - return result; - } - libusb_speed_t speed = LIBUSB_SPEED_FULL; - if ( full_status->status.high_speed_attached ) { - speed = LIBUSB_SPEED_HIGH; - } else if ( full_status->status.low_speed_attached ) { - speed = LIBUSB_SPEED_LOW; - } - // attach new device - result = usb_attach_device( device_number, port, speed ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to attach device: %s\r\n", strerror( result ) ) - #endif - // return result - return result; - } - // return success - return 0; -} - -/** - * @fn int attach_hub_check_connection(uint32_t, libusb_hub_device_t*, uint8_t) - * @brief Function to check hub connection - * @param device_number - * @param device_data - * @param port - * @return - */ -static int attach_hub_check_connection( - const uint32_t device_number, - libusb_hub_device_t* device_data, - const uint8_t port -) { - // cache hub device - const bool previously_connected = device_data->port_status[ port ].status.connected; - uint32_t roothub_device_number; - int result = usb_get_root_hub( &roothub_device_number ); - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to retrieve root hub: %s\r\n", strerror( result ) ) - #endif - // return result - return result; - } - // get port status - result = attach_hub_get_port_status( device_number, device_data, port ); - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to retrieve port status: %s\r\n", strerror( result ) ) - #endif - // return result - return result; - } - // cache full status - libusb_hub_port_full_status_t* port_status = &device_data->port_status[ port ]; - // handle connected to root device - STARTUP_PRINT( "device_number = %"PRIu32" connected = %d, previously_connected = %d\r\n", - device_number, port_status->status.connected ? 1 : 0, previously_connected ? 1 : 0 ) - // handle directly connected to root hub - if ( - device_number == roothub_device_number - && port_status->status.connected != previously_connected - ) { - STARTUP_PRINT( "Root hub which is connected and was previously not or vice versa\r\n" ) - port_status->change.connected_changed = true; - } - // handle connection changed - if ( port_status->change.connected_changed ) { - STARTUP_PRINT( "Connected changed!\r\n" ) - attach_hub_port_connection_changed( device_number, device_data, port ); - } - if ( port_status->change.enabled_changed ) { - STARTUP_PRINT( "ENABLED CHANGED!\r\n" ) - // clear enable change flag - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_ENABLE_CHANGE, port, false ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to clear enable change for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( device_number ) ) - #endif - } - - if ( ! port_status->status.enabled && port_status->status.connected && device_data->children[ port ] ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( - "%s. Port %d has been disabled but is connected. This can be caused by interference. Enabling it again\r\n", - usb_get_description( device_number ), port + 1 ) - #endif - // call connection changed - attach_hub_port_connection_changed( device_number, device_data, port ); - } - } - if ( port_status->status.suspended ) { - STARTUP_PRINT( "SUSPENDED!\r\n" ) - // clear enable change flag - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_SUSPEND, port, false ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to suspend port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( device_number ) ) - #endif - } - } - if ( port_status->change.over_current_changed ) { - STARTUP_PRINT( "OVER CURRENT CHANGED!\r\n" ) - // clear enable change flag - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_OVER_CURRENT_CHANGE, port, false ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to clear over current for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( device_number ) ) - #endif - } - // power on hub - result = attach_hub_power_on( device_number, device_data ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Unable to power on device %s: %s\r\n", - usb_get_description( device_number ), strerror( result ) ) - #endif - } - } - if ( port_status->change.reset_changed ) { - STARTUP_PRINT( "RESET CHANGED!\r\n" ) - // clear enable change flag - result = attach_hub_change_port_feature( - device_number, LIBUSB_HUB_PORT_FEATURE_RESET_CHANGE, port, false ); - // handle error - if ( 0 != result ) { - // debug output - #if defined ( HUB_ENABLE_DEBUG ) - STARTUP_PRINT( "Failed to clear reset for port %"PRIu8" for %s\r\n", - port + 1, usb_get_description( device_number ) ) - #endif - } - } - // return success - return 0; -} - /** * @fn void rpc_hub_attach(size_t, pid_t, size_t, size_t) * @brief Register rpc handler attach @@ -749,7 +134,7 @@ void rpc_hub_attach( memset( hub, 0, sizeof( *hub ) ); // read descriptor libusb_hub_descriptor_t* descriptor = nullptr; - result = attach_hub_read_descriptor( message->device_number, ( void** )&descriptor ); + result = hub_read_descriptor( message->device_number, ( void** )&descriptor ); // handle error if ( 0 != result ) { STARTUP_PRINT( "Unable to read hub descriptor\r\n" ) @@ -836,7 +221,7 @@ void rpc_hub_attach( STARTUP_PRINT( "Hub ports: %"PRIu8"\r\n", hub->descriptor->port_count ) #endif // retrieve status - result = attach_hub_get_status( message->device_number, hub ); + result = hub_get_status( message->device_number, hub ); // handle error if ( 0 != result ) { // debug output @@ -860,7 +245,7 @@ void rpc_hub_attach( !status->status.over_current ? "No" : "Yes" ) #endif // power on hub - result = attach_hub_power_on( message->device_number, hub ); + result = hub_power_on( message->device_number, hub ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -873,7 +258,7 @@ void rpc_hub_attach( return; } // fetch status again - result = attach_hub_get_status( message->device_number, hub ); + result = hub_get_status( message->device_number, hub ); if ( 0 != result ) { // debug output #if defined ( HUB_ENABLE_DEBUG ) @@ -896,7 +281,7 @@ void rpc_hub_attach( // check for connection for ( uint32_t port = 0; port < hub->max_children; port++ ) { STARTUP_PRINT( "Checking port %"PRIu32"\r\n", port ) - attach_hub_check_connection( message->device_number, hub, ( uint8_t )port ); + hub_check_connection( message->device_number, hub, ( uint8_t )port ); } // store hub in linked list hub_append( hub ); From 9559c69d039a085bbd2b99dd416f087d6f660a3a Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 18:42:55 +0200 Subject: [PATCH 031/144] - Implemented hid_get_driver within hid library for requesting the driver - Implemented hid get driver rpc within hid driver - Added helper to get hid driver by device number - Started implementing mouse and keyboard driver simultaneously - Added populate of device driver and data size in hub and hid attach --- bolthur/library/hid/hid.c | 59 ++++++++++++ bolthur/library/hid/hid.h | 1 + bolthur/server/libusbd.h | 6 ++ bolthur/server/usb/device/hid/hid/Makefile.am | 1 + bolthur/server/usb/device/hid/hid/hid.c | 26 +++++ bolthur/server/usb/device/hid/hid/hid.h | 1 + bolthur/server/usb/device/hid/hid/main.c | 3 +- bolthur/server/usb/device/hid/hid/rpc.h | 1 + .../usb/device/hid/hid/rpc/get/driver.c | 96 +++++++++++++++++++ .../usb/device/hid/hid/rpc/hid/attach.c | 4 +- bolthur/server/usb/device/hid/hid/rpc/init.c | 6 ++ .../device/hid/keyboard/rpc/keyboard/attach.c | 20 +++- .../usb/device/hid/mouse/rpc/mouse/attach.c | 20 +++- .../server/usb/device/hub/rpc/hub/attach.c | 2 + 14 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 bolthur/server/usb/device/hid/hid/rpc/get/driver.c diff --git a/bolthur/library/hid/hid.c b/bolthur/library/hid/hid.c index ec03f606..4ba8fa19 100644 --- a/bolthur/library/hid/hid.c +++ b/bolthur/library/hid/hid.c @@ -106,3 +106,62 @@ int hid_register_handler( const libusb_hid_usage_page_desktop_t type ) { // return success return 0; } + +/** + * @fn int hid_get_driver(uint32_t, uint32_t*) + * @brief Hid get driver + * @param device_number + * @param device_driver + * @return + */ +int hid_get_driver( uint32_t device_number, uint32_t* device_driver ) { + // validate parameters + if ( ! device_driver ) { + return EINVAL; + } + // debug message + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Get driver for %"PRIu32"\r\n", device_number ) + #endif + // allocate device + hid_get_driver_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->device_number = device_number; + // perform request + const int result = ioctl( + fd_hid, + IOCTL_BUILD_REQUEST( + HID_GET_DRIVER, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // return device driver + *device_driver = request->device_driver; + // free request + free( request ); + // return success + return 0; +} diff --git a/bolthur/library/hid/hid.h b/bolthur/library/hid/hid.h index 6464867e..2f47501a 100644 --- a/bolthur/library/hid/hid.h +++ b/bolthur/library/hid/hid.h @@ -24,5 +24,6 @@ int hid_init( void ); int hid_register_handler( libusb_hid_usage_page_desktop_t ); +int hid_get_driver( uint32_t, uint32_t* ); #endif diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index 1da39f47..8c745f5a 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -38,6 +38,7 @@ // hid rpc #define HID_REGISTER_HANDLER GENERIC_DEALLOCATE + 1 #define HID_UNREGISTER_HANDLER HID_REGISTER_HANDLER + 1 +#define HID_GET_DRIVER HID_UNREGISTER_HANDLER + 1 // hub rpc #define HUB_CHECK_CHANGE GENERIC_DEALLOCATE + 1 @@ -76,6 +77,11 @@ typedef struct { pid_t handler; } hid_unregister_device_handler_t; +typedef struct { + uint32_t device_number; + uint32_t device_driver; +} hid_get_driver_t; + // usbd rpc structures typedef struct { libusb_interface_class_t type; diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index 6e5f4081..c59b2f10 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -9,6 +9,7 @@ hid_LDADD = \ ${abs_top_builddir}/../library/usb/libusb.la \ ${abs_top_builddir}/../library/collection/avl/libavl.la hid_SOURCES = \ + rpc/get/driver.c \ rpc/handler/register.c \ rpc/handler/unregister.c \ rpc/hid/attach.c \ diff --git a/bolthur/server/usb/device/hid/hid/hid.c b/bolthur/server/usb/device/hid/hid/hid.c index aeb58e23..bfb2799a 100644 --- a/bolthur/server/usb/device/hid/hid/hid.c +++ b/bolthur/server/usb/device/hid/hid/hid.c @@ -622,3 +622,29 @@ void hid_append( libusb_hid_device_t* hid ) { found->next = hid; hid->prev = found; } + +/** + * @fn int hid_get(uint32_t, libusb_hid_device_t**) + * @brief Function to get hid device + * @param device_number + * @param hid + * @return + */ +int hid_get( const uint32_t device_number, libusb_hid_device_t** hid ) { + // setup current + libusb_hid_device_t* current = hid_head; + // loop while there is an entry + while ( current ) { + // handle match + if ( current->device_number == device_number ) { + // set pointer + *hid = current; + // return success + return 0; + } + // go to next + current = current->next; + } + // return error + return ENOENT; +} diff --git a/bolthur/server/usb/device/hid/hid/hid.h b/bolthur/server/usb/device/hid/hid/hid.h index ec528faf..cf65bfa4 100644 --- a/bolthur/server/usb/device/hid/hid/hid.h +++ b/bolthur/server/usb/device/hid/hid/hid.h @@ -72,5 +72,6 @@ void hid_enumerate_action_add_field( void* data, libusb_hid_report_tag_t, uint32 void hid_enumerate_report( void*, size_t, hid_report_action_t, void* ); int hid_parse_report_descriptor( libusb_hid_device_t*, void*, size_t ); void hid_append( libusb_hid_device_t* ); +int hid_get( uint32_t, libusb_hid_device_t** ); #endif diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c index 548389fa..eac7969d 100644 --- a/bolthur/server/usb/device/hid/hid/main.c +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -90,8 +90,9 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { GENERIC_DEALLOCATE, HID_REGISTER_HANDLER, HID_UNREGISTER_HANDLER, + HID_GET_DRIVER, }; - if ( !dev_add_file( HID_DEVICE_PATH, device_info, 5 ) ) { + if ( !dev_add_file( HID_DEVICE_PATH, device_info, 6 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/hid/hid/rpc.h b/bolthur/server/usb/device/hid/hid/rpc.h index d6f6a556..97d39e50 100644 --- a/bolthur/server/usb/device/hid/hid/rpc.h +++ b/bolthur/server/usb/device/hid/hid/rpc.h @@ -23,6 +23,7 @@ #include #include +void rpc_get_driver( size_t, pid_t, size_t, size_t ); void rpc_handler_register( size_t, pid_t, size_t, size_t ); void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); void rpc_hid_attach( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/usb/device/hid/hid/rpc/get/driver.c b/bolthur/server/usb/device/hid/hid/rpc/get/driver.c new file mode 100644 index 00000000..253f4a89 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/get/driver.c @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../hid.h" +#include "../../handler.h" +#include "../../rpc.h" +#include "../../global.h" +#include "../../../../../../libusbd.h" + +/** + * @fn void rpc_get_driver(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler get driver + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_driver( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info + ) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + hid_get_driver_t* message = ( hid_get_driver_t* )request->container; + // get device + libusb_hid_device_t* dev; + const int result = hid_get( message->device_number, &dev ); + if ( 0 != result ) { + error.status = -result; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // push into message + message->device_driver = dev->header.device_driver; + // calculate request size + const size_t request_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate response + vfs_ioctl_perform_response_t* response = malloc( + sizeof( vfs_ioctl_perform_response_t ) + request_size ); + // handle error + if ( ! response ) { + error.status = -ENOMEM; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, message, request_size ); + // return + bolthur_rpc_return( RPC_VFS_IOCTL, response, request_size + sizeof( vfs_ioctl_perform_response_t ), NULL, 0 ); + // free request and response + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c index 0b270817..c1c4f2d0 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c +++ b/bolthur/server/usb/device/hid/hid/rpc/hid/attach.c @@ -42,7 +42,7 @@ void rpc_hid_attach( pid_t origin, size_t data_info, [[maybe_unused]] size_t response_info - ) { +) { // handle no data if( ! data_info ) { STARTUP_PRINT( "NO DATA PASSED!\r\n" ) @@ -232,6 +232,8 @@ void rpc_hid_attach( memset( device, 0, sizeof( *device ) ); // populate device device->device_number = message->device_number; + device->header.device_driver = DEVICE_DRIVER_HID; + device->header.data_size = sizeof( *device ); // allocate report descriptor void* report_descriptor = malloc( descriptor->optional[ 0 ].length ); if ( ! report_descriptor ) { diff --git a/bolthur/server/usb/device/hid/hid/rpc/init.c b/bolthur/server/usb/device/hid/hid/rpc/init.c index cf35aecc..52016a59 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/init.c +++ b/bolthur/server/usb/device/hid/hid/rpc/init.c @@ -58,5 +58,11 @@ bool rpc_init( void ) { STARTUP_PRINT( "Unable to register unregister device handler!\r\n" ) return false; } + // register get driver + bolthur_rpc_bind( HID_GET_DRIVER, rpc_get_driver, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get driver!\r\n" ) + return false; + } return true; } diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c index 609a620c..607d50b8 100644 --- a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c @@ -25,6 +25,7 @@ #include "../../rpc.h" #include "../../global.h" #include "../../../../../../libusbd.h" +#include "../../../../../../../library/hid/hid.h" #include "../../../../../../../library/usb/usb.h" /** @@ -66,7 +67,24 @@ void rpc_keyboard_attach( return; } // allocate space for pull_request - //const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + // get hid driver + uint32_t device_driver; + int result = hid_get_driver( message->device_number, &device_driver ); + if ( 0 != result ) { + STARTUP_PRINT( "Error while fetching driver: %s\r\n", strerror( result ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // handle invalid device driver + if ( device_driver != DEVICE_DRIVER_HID ) { + STARTUP_PRINT( "\"%s\" is not a hid device. Keyboard driver is build upon hid driver\r\n", + usb_get_description( message->device_number ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } /// FIXME: IMPLEMENT STARTUP_PRINT( "KEYBOARD ATTACH FOLLOWING!\r\n" ) free( request ); diff --git a/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c index fbc5750e..15f18326 100644 --- a/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c +++ b/bolthur/server/usb/device/hid/mouse/rpc/mouse/attach.c @@ -25,6 +25,7 @@ #include "../../rpc.h" #include "../../global.h" #include "../../../../../../libusbd.h" +#include "../../../../../../../library/hid/hid.h" #include "../../../../../../../library/usb/usb.h" /** @@ -66,7 +67,24 @@ void rpc_mouse_attach( return; } // allocate space for pull_request - //const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + const usb_generic_attach_t* message = ( usb_generic_attach_t* )request->container; + // get hid driver + uint32_t device_driver; + int result = hid_get_driver( message->device_number, &device_driver ); + if ( 0 != result ) { + STARTUP_PRINT( "Error while fetching driver: %s\r\n", strerror( result ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // handle invalid device driver + if ( device_driver != DEVICE_DRIVER_HID ) { + STARTUP_PRINT( "\"%s\" is not a hid device. Mouse driver is build upon hid driver\r\n", + usb_get_description( message->device_number ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } /// FIXME: IMPLEMENT STARTUP_PRINT( "MOUSE ATTACH FOLLOWING!\r\n" ) free( request ); diff --git a/bolthur/server/usb/device/hub/rpc/hub/attach.c b/bolthur/server/usb/device/hub/rpc/hub/attach.c index b261e035..445301e8 100644 --- a/bolthur/server/usb/device/hub/rpc/hub/attach.c +++ b/bolthur/server/usb/device/hub/rpc/hub/attach.c @@ -144,6 +144,8 @@ void rpc_hub_attach( return; } // populate hub max children and device number + hub->header.device_driver = DEVICE_DRIVER_HUB; + hub->header.data_size = sizeof( *hub ); hub->descriptor = descriptor; hub->max_children = hub->descriptor->port_count; hub->device_number = message->device_number; From 5a565b979b7f28b6eb959ab935a494a0f126ffac Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sat, 2 Aug 2025 21:13:39 +0200 Subject: [PATCH 032/144] - Implemented rpc calls to get application, report and report count - Added wrapper functions to hid library to abstract away the fetching - Added fields_length to report entry indicating the amount of fields - Added function to destroy keyboard device - Added function to get new keyboard index - Added function to duplicate a report for keyboard - Continued working on keyboard attach --- bolthur/library/hid/hid.c | 226 +++++++++++++++ bolthur/library/hid/hid.h | 3 + bolthur/server/libusb.h | 1 + bolthur/server/libusbd.h | 19 ++ bolthur/server/usb/device/hid/hid/Makefile.am | 3 + bolthur/server/usb/device/hid/hid/hid.c | 1 + bolthur/server/usb/device/hid/hid/main.c | 5 +- bolthur/server/usb/device/hid/hid/rpc.h | 3 + .../usb/device/hid/hid/rpc/get/application.c | 96 +++++++ .../usb/device/hid/hid/rpc/get/driver.c | 2 +- .../usb/device/hid/hid/rpc/get/report.c | 113 ++++++++ .../usb/device/hid/hid/rpc/get/report_count.c | 96 +++++++ bolthur/server/usb/device/hid/hid/rpc/init.c | 18 ++ .../server/usb/device/hid/keyboard/keyboard.c | 79 ++++++ .../server/usb/device/hid/keyboard/keyboard.h | 3 + .../device/hid/keyboard/rpc/keyboard/attach.c | 259 +++++++++++++++++- notes-usb.md | 4 + 17 files changed, 927 insertions(+), 4 deletions(-) create mode 100644 bolthur/server/usb/device/hid/hid/rpc/get/application.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/get/report.c create mode 100644 bolthur/server/usb/device/hid/hid/rpc/get/report_count.c diff --git a/bolthur/library/hid/hid.c b/bolthur/library/hid/hid.c index 4ba8fa19..3222f744 100644 --- a/bolthur/library/hid/hid.c +++ b/bolthur/library/hid/hid.c @@ -165,3 +165,229 @@ int hid_get_driver( uint32_t device_number, uint32_t* device_driver ) { // return success return 0; } + +/** + * @fn int hid_get_application(uint32_t, libusb_hid_full_usage_t*) + * @brief Function to get hid application data + * @param device_number + * @param application + * @return + */ +int hid_get_application( + uint32_t device_number, + libusb_hid_full_usage_t* application +) { + // validate parameters + if ( ! application ) { + return EINVAL; + } + // debug message + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Get application from %"PRIu32"\r\n", device_number ) + #endif + // allocate device + hid_get_application_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->device_number = device_number; + // perform request + const int result = ioctl( + fd_hid, + IOCTL_BUILD_REQUEST( + HID_GET_APPLICATION, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // return device driver + memcpy( application, &request->application, sizeof( *application ) ); + // free request + free( request ); + // return success + return 0; +} + +/** + * @fn int hid_get_report_count(uint32_t, uint8_t*) + * @brief Method to get report count of hid + * @param device_number + * @param report_count + * @return + */ +int hid_get_report_count( uint32_t device_number, uint8_t* report_count ) { + // validate parameters + if ( ! report_count ) { + return EINVAL; + } + // debug message + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Get report count from %"PRIu32"\r\n", device_number ) + #endif + // allocate device + hid_get_report_count_t* request = malloc( sizeof( *request ) ); + // handle error + if ( ! request ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // return nomem + return ENOMEM; + } + // clear out + memset( request, 0, sizeof( *request ) ); + // copy over necessary data + request->device_number = device_number; + // perform request + const int result = ioctl( + fd_hid, + IOCTL_BUILD_REQUEST( + HID_GET_REPORT_COUNT, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == result ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // free request + free( request ); + return EIO; + } + // return device driver + *report_count = request->report_count; + // free request + free( request ); + // return success + return 0; +} + +/** + * @fn int hid_get_report(uint32_t, uint8_t, libusb_hid_parser_report_t**) + * @brief Function to get hid report + * @param device_number + * @param report + * @param result + * @return + */ +int hid_get_report( + const uint32_t device_number, + const uint8_t report, + libusb_hid_parser_report_t** result +) { + // validate parameter + if ( ! result ) { + return EINVAL; + } + // allocate shared memory + const size_t shm_id = _syscall_memory_shared_create( 0x1000 ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to acquire shared memory!\r\n" ) + #endif + // return error + return e; + } + // attach it + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( shm_id, ( uintptr_t )NULL ); + // handle error + if ( errno ) { + const int e = errno; + // debug output + #if defined( LIBUSB_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to attach shared memory!\r\n" ) + #endif + // return error + return e; + } + // allocate request + hid_get_report_t* request = malloc( sizeof( *request ) ); + if ( ! request ) { + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate request\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // return enomem + return ENOMEM; + } + // clear out request + memset( request, 0, sizeof( *request ) ); + // populate request + request->device_number = device_number; + request->report = report; + request->shm_id = shm_id; + // perform request + const int ioctl_result = ioctl( + fd_hid, + IOCTL_BUILD_REQUEST( + HID_GET_REPORT, + sizeof( *request ), + IOCTL_RDWR + ), + request + ); + // handle ioctl error + if ( -1 == ioctl_result ) { + // debug output + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "errno = %s\r\n", strerror( errno ) ); + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( request ); + return EIO; + } + // pointer to result + libusb_hid_parser_report_t* parser = ( libusb_hid_parser_report_t* )shm_addr; + // allocate space + *result = malloc( sizeof( *result ) + parser->fields_length * sizeof( libusb_hid_parser_fields_t ) ); + if ( ! *result ) { + #if defined( LIBHID_ENABLE_DEBUG ) + STARTUP_PRINT( "Unable to allocate report fields\r\n" ) + #endif + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( request ); + return ENOMEM; + } + // copy over content + memcpy( *result, parser, sizeof( *result ) + parser->fields_length * sizeof( libusb_hid_parser_fields_t ) ); + // detach shared memory + _syscall_memory_shared_detach( shm_id ); + // free request + free( request ); + // return success + return 0; +} diff --git a/bolthur/library/hid/hid.h b/bolthur/library/hid/hid.h index 2f47501a..17b38e5e 100644 --- a/bolthur/library/hid/hid.h +++ b/bolthur/library/hid/hid.h @@ -25,5 +25,8 @@ int hid_init( void ); int hid_register_handler( libusb_hid_usage_page_desktop_t ); int hid_get_driver( uint32_t, uint32_t* ); +int hid_get_application( uint32_t, libusb_hid_full_usage_t* ); +int hid_get_report_count( uint32_t, uint8_t* ); +int hid_get_report( uint32_t, uint8_t, libusb_hid_parser_report_t** ); #endif diff --git a/bolthur/server/libusb.h b/bolthur/server/libusb.h index c6818c92..a6888d42 100644 --- a/bolthur/server/libusb.h +++ b/bolthur/server/libusb.h @@ -776,6 +776,7 @@ typedef struct { libusb_hid_report_type_t type; uint8_t report_length; uint8_t* report_buffer; + size_t fields_length; libusb_hid_parser_fields_t fields[] __aligned(4); } libusb_hid_parser_report_t; diff --git a/bolthur/server/libusbd.h b/bolthur/server/libusbd.h index 8c745f5a..9ed8914b 100644 --- a/bolthur/server/libusbd.h +++ b/bolthur/server/libusbd.h @@ -39,6 +39,9 @@ #define HID_REGISTER_HANDLER GENERIC_DEALLOCATE + 1 #define HID_UNREGISTER_HANDLER HID_REGISTER_HANDLER + 1 #define HID_GET_DRIVER HID_UNREGISTER_HANDLER + 1 +#define HID_GET_APPLICATION HID_GET_DRIVER + 1 +#define HID_GET_REPORT_COUNT HID_GET_APPLICATION + 1 +#define HID_GET_REPORT HID_GET_REPORT_COUNT + 1 // hub rpc #define HUB_CHECK_CHANGE GENERIC_DEALLOCATE + 1 @@ -82,6 +85,22 @@ typedef struct { uint32_t device_driver; } hid_get_driver_t; +typedef struct { + uint32_t device_number; + libusb_hid_full_usage_t application; +} hid_get_application_t; + +typedef struct { + uint32_t device_number; + uint8_t report_count; +} hid_get_report_count_t; + +typedef struct { + uint32_t device_number; + uint8_t report; + size_t shm_id; +} hid_get_report_t; + // usbd rpc structures typedef struct { libusb_interface_class_t type; diff --git a/bolthur/server/usb/device/hid/hid/Makefile.am b/bolthur/server/usb/device/hid/hid/Makefile.am index c59b2f10..556fe6c7 100644 --- a/bolthur/server/usb/device/hid/hid/Makefile.am +++ b/bolthur/server/usb/device/hid/hid/Makefile.am @@ -9,7 +9,10 @@ hid_LDADD = \ ${abs_top_builddir}/../library/usb/libusb.la \ ${abs_top_builddir}/../library/collection/avl/libavl.la hid_SOURCES = \ + rpc/get/application.c \ rpc/get/driver.c \ + rpc/get/report.c \ + rpc/get/report_count.c \ rpc/handler/register.c \ rpc/handler/unregister.c \ rpc/hid/attach.c \ diff --git a/bolthur/server/usb/device/hid/hid/hid.c b/bolthur/server/usb/device/hid/hid/hid.c index bfb2799a..a69e953f 100644 --- a/bolthur/server/usb/device/hid/hid/hid.c +++ b/bolthur/server/usb/device/hid/hid/hid.c @@ -545,6 +545,7 @@ int hid_parse_report_descriptor( result->report[ idx ]->type = report_field->data[ idx ].report_type; result->report[ idx ]->report_length = 0; result->report[ idx ]->report_buffer = NULL; + result->report[ idx ]->fields_length = report_field->data[ idx ].field_count; } // free again report fields free( report_field ); diff --git a/bolthur/server/usb/device/hid/hid/main.c b/bolthur/server/usb/device/hid/hid/main.c index eac7969d..3e9291ee 100644 --- a/bolthur/server/usb/device/hid/hid/main.c +++ b/bolthur/server/usb/device/hid/hid/main.c @@ -91,8 +91,11 @@ int main( [[maybe_unused]] int argc, [[maybe_unused]] char* argv[] ) { HID_REGISTER_HANDLER, HID_UNREGISTER_HANDLER, HID_GET_DRIVER, + HID_GET_APPLICATION, + HID_GET_REPORT_COUNT, + HID_GET_REPORT, }; - if ( !dev_add_file( HID_DEVICE_PATH, device_info, 6 ) ) { + if ( !dev_add_file( HID_DEVICE_PATH, device_info, 9 ) ) { STARTUP_PRINT( "Unable to add dev usbd\r\n" ) return -1; } diff --git a/bolthur/server/usb/device/hid/hid/rpc.h b/bolthur/server/usb/device/hid/hid/rpc.h index 97d39e50..2bba27d3 100644 --- a/bolthur/server/usb/device/hid/hid/rpc.h +++ b/bolthur/server/usb/device/hid/hid/rpc.h @@ -23,7 +23,10 @@ #include #include +void rpc_get_application( size_t, pid_t, size_t, size_t ); void rpc_get_driver( size_t, pid_t, size_t, size_t ); +void rpc_get_report( size_t, pid_t, size_t, size_t ); +void rpc_get_report_count( size_t, pid_t, size_t, size_t ); void rpc_handler_register( size_t, pid_t, size_t, size_t ); void rpc_handler_unregister( size_t, pid_t, size_t, size_t ); void rpc_hid_attach( size_t, pid_t, size_t, size_t ); diff --git a/bolthur/server/usb/device/hid/hid/rpc/get/application.c b/bolthur/server/usb/device/hid/hid/rpc/get/application.c new file mode 100644 index 00000000..3375e939 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/get/application.c @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../hid.h" +#include "../../handler.h" +#include "../../rpc.h" +#include "../../global.h" +#include "../../../../../../libusbd.h" + +/** + * @fn void rpc_get_application(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler get application + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_application( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + hid_get_application_t* message = ( hid_get_application_t* )request->container; + // get device + libusb_hid_device_t* dev; + const int result = hid_get( message->device_number, &dev ); + if ( 0 != result ) { + error.status = -result; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // push into message + memcpy( &message->application, &dev->parser_result->application, sizeof( message->application ) ); + // calculate request size + const size_t request_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate response + vfs_ioctl_perform_response_t* response = malloc( + sizeof( vfs_ioctl_perform_response_t ) + request_size ); + // handle error + if ( ! response ) { + error.status = -ENOMEM; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, message, request_size ); + // return + bolthur_rpc_return( RPC_VFS_IOCTL, response, request_size + sizeof( vfs_ioctl_perform_response_t ), NULL, 0 ); + // free request and response + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/get/driver.c b/bolthur/server/usb/device/hid/hid/rpc/get/driver.c index 253f4a89..8d432e17 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/get/driver.c +++ b/bolthur/server/usb/device/hid/hid/rpc/get/driver.c @@ -41,7 +41,7 @@ void rpc_get_driver( pid_t origin, size_t data_info, [[maybe_unused]] size_t response_info - ) { +) { vfs_ioctl_perform_response_t error = { .status = -EINVAL }; // handle no data if( ! data_info ) { diff --git a/bolthur/server/usb/device/hid/hid/rpc/get/report.c b/bolthur/server/usb/device/hid/hid/rpc/get/report.c new file mode 100644 index 00000000..95ef4616 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/get/report.c @@ -0,0 +1,113 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../hid.h" +#include "../../handler.h" +#include "../../rpc.h" +#include "../../global.h" +#include "../../../../../../libusbd.h" + +/** + * @fn void rpc_get_report(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler get report + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_report( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + hid_get_report_t* message = ( hid_get_report_t* )request->container; + // get device + libusb_hid_device_t* dev; + const int result = hid_get( message->device_number, &dev ); + if ( 0 != result ) { + error.status = -result; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // handle report greater than report count + if ( message->report > dev->parser_result->report_count ) { + error.status = -EINVAL; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // attach shared memory + void* shm_addr = _syscall_memory_shared_attach( message->shm_id, ( uintptr_t )NULL ); + if ( errno ) { + error.status = -errno; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // copy over parser + memcpy( shm_addr, dev->parser_result->report[ message->report ], sizeof( libusb_hid_parser_report_t ) + + dev->parser_result->report[ message->report ]->fields_length * sizeof( libusb_hid_parser_fields_t ) ); + // calculate request size + const size_t request_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate response + vfs_ioctl_perform_response_t* response = malloc( + sizeof( vfs_ioctl_perform_response_t ) + request_size ); + // handle error + if ( ! response ) { + error.status = -ENOMEM; + _syscall_memory_shared_detach( message->shm_id ); + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, message, request_size ); + // return + bolthur_rpc_return( RPC_VFS_IOCTL, response, request_size + sizeof( vfs_ioctl_perform_response_t ), NULL, 0 ); + // free request and response + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/get/report_count.c b/bolthur/server/usb/device/hid/hid/rpc/get/report_count.c new file mode 100644 index 00000000..e91cc242 --- /dev/null +++ b/bolthur/server/usb/device/hid/hid/rpc/get/report_count.c @@ -0,0 +1,96 @@ +/** + * Copyright (C) 2018 - 2025 bolthur project. + * + * This file is part of bolthur/kernel. + * + * bolthur/kernel is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * bolthur/kernel is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with bolthur/kernel. If not, see . + */ + +// system includes +#include +#include +#include +// local includes +#include "../../hid.h" +#include "../../handler.h" +#include "../../rpc.h" +#include "../../global.h" +#include "../../../../../../libusbd.h" + +/** + * @fn void rpc_get_report_count(size_t, pid_t, size_t, size_t) + * @brief Register rpc handler get report count + * @param type message type + * @param origin origin of the message + * @param data_info data id + * @param response_info response info + */ +void rpc_get_report_count( + [[maybe_unused]] size_t type, + pid_t origin, + size_t data_info, + [[maybe_unused]] size_t response_info +) { + vfs_ioctl_perform_response_t error = { .status = -EINVAL }; + // handle no data + if( ! data_info ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // validate origin + if ( ! bolthur_rpc_validate_origin( origin, data_info ) ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // get data from mailbox + size_t data_size; + vfs_ioctl_perform_request_t* request = bolthur_rpc_fetch_from_mailbox( data_info, &data_size, true, NULL ); + if ( ! request ) { + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // allocate space for pull_request + hid_get_report_count_t* message = ( hid_get_report_count_t* )request->container; + // get device + libusb_hid_device_t* dev; + const int result = hid_get( message->device_number, &dev ); + if ( 0 != result ) { + error.status = -result; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // push into message + message->report_count = dev->parser_result->report_count; + // calculate request size + const size_t request_size = data_size - sizeof( vfs_ioctl_perform_request_t ); + // allocate response + vfs_ioctl_perform_response_t* response = malloc( + sizeof( vfs_ioctl_perform_response_t ) + request_size ); + // handle error + if ( ! response ) { + error.status = -ENOMEM; + free( request ); + bolthur_rpc_return( RPC_VFS_IOCTL, &error, sizeof( error ), NULL, 0 ); + return; + } + // populate response + response->status = 0; + memcpy( response->container, message, request_size ); + // return + bolthur_rpc_return( RPC_VFS_IOCTL, response, request_size + sizeof( vfs_ioctl_perform_response_t ), NULL, 0 ); + // free request and response + free( request ); + free( response ); +} diff --git a/bolthur/server/usb/device/hid/hid/rpc/init.c b/bolthur/server/usb/device/hid/hid/rpc/init.c index 52016a59..cfbdcb99 100644 --- a/bolthur/server/usb/device/hid/hid/rpc/init.c +++ b/bolthur/server/usb/device/hid/hid/rpc/init.c @@ -64,5 +64,23 @@ bool rpc_init( void ) { STARTUP_PRINT( "Unable to register get driver!\r\n" ) return false; } + // register get application + bolthur_rpc_bind( HID_GET_APPLICATION, rpc_get_application, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get application!\r\n" ) + return false; + } + // register get report count + bolthur_rpc_bind( HID_GET_REPORT_COUNT, rpc_get_report_count, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get report count!\r\n" ) + return false; + } + // register get report + bolthur_rpc_bind(HID_GET_REPORT, rpc_get_report, true ); + if ( errno ) { + STARTUP_PRINT( "Unable to register get report!\r\n" ) + return false; + } return true; } diff --git a/bolthur/server/usb/device/hid/keyboard/keyboard.c b/bolthur/server/usb/device/hid/keyboard/keyboard.c index 7edb41e0..e43a8b87 100644 --- a/bolthur/server/usb/device/hid/keyboard/keyboard.c +++ b/bolthur/server/usb/device/hid/keyboard/keyboard.c @@ -17,6 +17,10 @@ * along with bolthur/kernel. If not, see . */ +#include +#include +#include +#include #include "keyboard.h" libusb_keyboard_device_t* keyboard_head = NULL; @@ -45,3 +49,78 @@ void keyboard_append( libusb_keyboard_device_t* keyboard ) { found->next = keyboard; keyboard->prev = found; } + +/** + * @fn void keyboard_destroy(libusb_keyboard_device_t*) + * @brief Method to destroy keyboard device + * @param device + */ +void keyboard_destroy( libusb_keyboard_device_t* device ) { + // handle no device + if ( ! device ) { + return; + } + // free up key fields + for ( size_t idx = 0; idx < 9; idx++ ) { + if ( device->key_field[ idx ] ) { + free( device->key_field[ idx ] ); + } + } + // free up led fields + for ( size_t idx = 0; idx < 8; idx++ ) { + if ( device->led_field[ idx ] ) { + free( device->led_field[ idx ] ); + } + } + // free device itself + free( device ); +} + +/** + * @fn int keyboard_new_index(uint32_t*); + * @brief Function to get new index + * @param index + * @return + */ +int keyboard_new_index( uint32_t* index ) { + // validate parameters + if ( ! index ) { + return EINVAL; + } + // initialize max index + uint32_t max_index = 0; + // loop through list and collect max index + const libusb_keyboard_device_t* current = keyboard_head; + while ( current ) { + // determine max index + max_index = ( uint32_t )fmax( max_index, current->index ); + // go to next + current = current->next; + } + // populate index + *index = max_index; + // return success + return 0; +} + +/** + * @fn int keyboard_duplicate_report(libusb_hid_parser_fields_t**, libusb_hid_parser_fields_t*) + * @brief Function to duplicate report + * @param destination + * @param source + * @return + */ +int keyboard_duplicate_report( + libusb_hid_parser_fields_t** destination, + const libusb_hid_parser_fields_t* source +) { + // allocate space + *destination = malloc( sizeof( libusb_hid_parser_fields_t ) ); + if ( ! *destination ) { + return ENOMEM; + } + // copy over content + memcpy( *destination, source, sizeof( libusb_hid_parser_fields_t ) ); + // return success + return 0; +} diff --git a/bolthur/server/usb/device/hid/keyboard/keyboard.h b/bolthur/server/usb/device/hid/keyboard/keyboard.h index 997c93bc..e269fbfb 100644 --- a/bolthur/server/usb/device/hid/keyboard/keyboard.h +++ b/bolthur/server/usb/device/hid/keyboard/keyboard.h @@ -25,5 +25,8 @@ #define KEYBOARD_ENABLE_DEBUG 1 void keyboard_append( libusb_keyboard_device_t* ); +void keyboard_destroy( libusb_keyboard_device_t* ); +int keyboard_new_index( uint32_t* ); +int keyboard_duplicate_report( libusb_hid_parser_fields_t**, const libusb_hid_parser_fields_t* ); #endif diff --git a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c index 607d50b8..799886cc 100644 --- a/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c +++ b/bolthur/server/usb/device/hid/keyboard/rpc/keyboard/attach.c @@ -24,6 +24,7 @@ // local includes #include "../../rpc.h" #include "../../global.h" +#include "../../keyboard.h" #include "../../../../../../libusbd.h" #include "../../../../../../../library/hid/hid.h" #include "../../../../../../../library/usb/usb.h" @@ -85,8 +86,262 @@ void rpc_keyboard_attach( _syscall_rpc_cleanup(); return; } - /// FIXME: IMPLEMENT - STARTUP_PRINT( "KEYBOARD ATTACH FOLLOWING!\r\n" ) + // get application + libusb_hid_full_usage_t application; + result = hid_get_application( message->device_number, &application ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get application data: %s\r\n", strerror( result ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // check application data + if ( + ( + application.page != LIBUSB_HID_USAGE_PAGE_GENERIC_DESKTOP_CONTROL + && application.page != LIBUSB_HID_USAGE_PAGE_UNDEFINED + ) || application.desktop != LIBUSB_HID_USAGE_PAGE_DESKTOP_KEYBOARD + ) { + STARTUP_PRINT( "\"%s\" does not seem to be a keyboard\r\n", + usb_get_description( message->device_number ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // get report count + uint8_t report_count; + result = hid_get_report_count( message->device_number, &report_count ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get report count of device: %s\r\n", + strerror( result ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // check report count + if ( 0 >= report_count ) { + STARTUP_PRINT( "\"%s\" does not have enough outputs to be a keyboard\r\n", + usb_get_description( message->device_number ) ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // allocate device + libusb_keyboard_device_t* device = malloc( sizeof( *device ) ); + if ( ! device ) { + STARTUP_PRINT( "Unable to allocate memory for device\r\n" ) + free( request ); + _syscall_rpc_cleanup(); + return; + } + // clear out keyboard driver space + memset( device, 0, sizeof( *device ) ); + // populate header + device->header.device_driver = DEVICE_DRIVER_KEYBOARD; + device->header.data_size = sizeof( *device ); + // determine new index + result = keyboard_new_index( &device->index ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to determine new index: %s\r\n", strerror( result ) ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // iterate over reports + for ( uint8_t idx = 0; idx < report_count; ++idx ) { + // query report from hid + libusb_hid_parser_report_t* report; + result = hid_get_report( message->device_number, idx, &report ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to get report %"PRIu8" from hid\r\n", idx ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // some debug output + STARTUP_PRINT( "type = %x, report = %"PRIu8", fields = %"PRIu8"\r\n", + report->type, idx, report->field_count ) + // handle input + if ( report->type == LIBUSB_HID_REPORT_TYPE_INPUT && ! device->key_report ) { + for ( uint8_t inner = 0; inner < report->field_count; ++inner ) { + if ( + report->fields[ inner ].usage.page == LIBUSB_HID_USAGE_PAGE_KEYBOARD_CONTROL + || report->fields[ inner ].usage.page == LIBUSB_HID_USAGE_PAGE_UNDEFINED + ) { + if ( report->fields[ inner ].attribute.variable ) { + if ( + report->fields[ inner ].usage.keyboard >= LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_CONTROL + && report->fields[ inner ].usage.keyboard <= LIBUSB_HID_USAGE_PAGE_KEYBOARD_RIGHT_CONTROL + ) { + STARTUP_PRINT( + "Modifier %d detected. Offset = %"PRIx8", size = %"PRIx8"\r\n", + report->fields[ inner ].usage.keyboard, + report->fields[ inner ].offset, + report->fields[ inner ].size + ) + // allocate space + const size_t key_field_index = report->fields[ inner ].usage.keyboard - LIBUSB_HID_USAGE_PAGE_KEYBOARD_LEFT_CONTROL; + result = keyboard_duplicate_report( &device->key_field[ key_field_index ], &report->fields[ inner ] ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + } + } else { + STARTUP_PRINT( "Key input detected\r\n" ) + result = keyboard_duplicate_report( &device->key_field[ 8 ], &report->fields[ inner ] ); + // handle error + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + } + } + } + } else if ( report->type == LIBUSB_HID_REPORT_TYPE_OUTPUT && ! device->led_report ) { + // data->LedReport = parse->Report[i]; + for ( uint8_t inner = 0; inner < report->field_count; ++inner ) { + // skip non led stuff + if ( report->fields[ inner ].usage.page != LIBUSB_HID_USAGE_PAGE_LED ) { + continue; + } + // handle led page + switch ( report->fields[ inner ].usage.led ) { + case LIBUSB_HID_USAGE_PAGE_LED_NUMBER_LOCK: + STARTUP_PRINT( "Number lock led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 0 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.num_lock = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_CAPSLOCK: + STARTUP_PRINT( "Capslock lock led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 1 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.caps_lock = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_SCROLL_LOCK: + STARTUP_PRINT( "Scroll lock led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 2 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.scroll_lock = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_COMPOSE: + STARTUP_PRINT( "Compose led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 3 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.compose = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_KANA: + STARTUP_PRINT( "Kana led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 4 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.kana = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_POWER: + STARTUP_PRINT( "Power led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 5 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.power = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_SHIFT: + STARTUP_PRINT( "Shift led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 6 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.shift = true; + break; + case LIBUSB_HID_USAGE_PAGE_LED_MUTE: + STARTUP_PRINT( "Mute led detected\r\n") + // duplicate report + result = keyboard_duplicate_report( &device->led_field[ 7 ], &report->fields[ inner ] ); + if ( 0 != result ) { + STARTUP_PRINT( "Unable to duplicate report\r\n" ) + free( request ); + keyboard_destroy( device ); + _syscall_rpc_cleanup(); + return; + } + // set supported flag + device->led.mute = true; + break; + default: + break; + } + } + } + /// FIXME: IMPLEMENT + // free report again + free( report ); + } + // append device to list + keyboard_append( device ); + // free request and cleanup free( request ); _syscall_rpc_cleanup(); } diff --git a/notes-usb.md b/notes-usb.md index e48a60b5..cd0212b5 100644 --- a/notes-usb.md +++ b/notes-usb.md @@ -27,3 +27,7 @@ - setup rpc handler - do basic initialization of dwhci - provide /dev/usb/hcd + +## To be done + +- Use interrupts in hcd server From 8da38ec2a57080d5b912876ebb8e149f134caa6f Mon Sep 17 00:00:00 2001 From: Christian Freitag Date: Sun, 10 Aug 2025 08:42:08 +0200 Subject: [PATCH 033/144] - Implemented mask specific interrupt within syscall_interrupt_acquire to enable it - Extended rpi usb hcd server to register for interrupt - Added enable of core and host interrupts - Replaced last magic number in interrupt_validate_number - Added fetch of endpoint descriptor within keyboard attach for querying endpoint address number and interval - Replaced EARLY_STARTUP_PRINT WITHIN hid by STARTUP_PRINT - Replaced bolthur_rpc_wait_block by loop starting keyboard polling with wait for rpc call if all are started - Extended keyboard device object by descriptor and last poll - Added cache of endpoint descriptor in keyboard attach - Added setup of last poll within keyboard attach with 0 --- .idea/editor.xml | 1 + .idea/kernel.iml | 2 + .idea/markdown.xml | 8 +++ .idea/modules.xml | 8 +++ bolthur/kernel/arch/arm/v7/rpc/generic.c | 2 +- bolthur/kernel/interrupt.c | 23 +++--- bolthur/kernel/platform/raspi/interrupt.c | 6 +- bolthur/kernel/syscall/interrupt.c | 8 ++- bolthur/server/libusb.h | 2 + bolthur/server/platform/raspi/libhcd.h | 4 +- bolthur/server/platform/raspi/usb/hcd/dwhci.c | 72 +++++++++++++++++++ bolthur/server/usb/device/hid/hid/hid.c | 4 +- .../server/usb/device/hid/keyboard/keyboard.h | 2 + bolthur/server/usb/device/hid/keyboard/main.c | 27 +++++-- .../device/hid/keyboard/rpc/keyboard/attach.c | 18 ++++- notes-usb.md | 5 +- 16 files changed, 168 insertions(+), 24 deletions(-) create mode 100644 .idea/kernel.iml create mode 100644 .idea/markdown.xml create mode 100644 .idea/modules.xml diff --git a/.idea/editor.xml b/.idea/editor.xml index f9a23742..a6d90538 100644 --- a/.idea/editor.xml +++ b/.idea/editor.xml @@ -117,6 +117,7 @@