commit
5e714edfa6
33 changed files with 2167 additions and 1514 deletions
17
.travis.yml
Normal file
17
.travis.yml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
before_install:
|
||||
- sudo add-apt-repository -y ppa:terry.guo/gcc-arm-embedded
|
||||
- sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key 6D1D8367A3421AFB
|
||||
- sudo apt-get update -o Dir::Etc::sourcelist="sources.list.d/terry_guo-gcc-arm-embedded-precise.list" -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"
|
||||
- sudo apt-get install gcc-arm-none-eabi
|
||||
script:
|
||||
- cd build && cmake $FLAGS_matrix .. && make
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- FLAGS_matrix="-DUSE_USART_DEBUG=FALSE -DUSE_STM32F4_HS=TRUE -DUSE_STM32F4_FS=TRUE"
|
||||
- FLAGS_matrix="-DUSE_USART_DEBUG=TRUE -DUSE_STM32F4_HS=TRUE -DUSE_STM32F4_FS=TRUE"
|
||||
- FLAGS_matrix="-DUSE_USART_DEBUG=TRUE -DUSE_STM32F4_HS=FALSE -DUSE_STM32F4_FS=TRUE"
|
||||
- FLAGS_matrix="-DUSE_USART_DEBUG=TRUE -DUSE_STM32F4_HS=TRUE -DUSE_STM32F4_FS=FALSE"
|
||||
94
CMakeLists.txt
Normal file
94
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
cmake_minimum_required (VERSION 2.6)
|
||||
|
||||
# initialize compiler
|
||||
include (cmake/toolchain.cmake)
|
||||
|
||||
# initialize flashing
|
||||
include (cmake/openocd_flash.cmake)
|
||||
|
||||
# initilize doc
|
||||
include (cmake/doc.cmake)
|
||||
|
||||
project (libusbhost C)
|
||||
|
||||
# Declare cached variables
|
||||
|
||||
set (USE_STM32F4_FS TRUE CACHE BOOL "Use USB full speed (FS) host periphery")
|
||||
set (USE_STM32F4_HS TRUE CACHE BOOL "Use USB high speed (HS) host periphery")
|
||||
set (USE_USART_DEBUG TRUE CACHE BOOL "Use debug uart output")
|
||||
|
||||
# Set compiler and linker flags
|
||||
|
||||
set (FP_FLAGS
|
||||
"-mfloat-abi=hard -mfpu=fpv4-sp-d16 -mfp16-format=alternative"
|
||||
)
|
||||
|
||||
set (ARCH_FLAGS
|
||||
"-mthumb -mcpu=cortex-m4 ${FP_FLAGS}"
|
||||
)
|
||||
set (COMMON_FLAGS
|
||||
"-O2 -g -Wextra -Wshadow -Wredundant-decls -fno-common -ffunction-sections -fdata-sections"
|
||||
)
|
||||
|
||||
set (CMAKE_C_FLAGS
|
||||
"${COMMON_FLAGS} ${ARCH_FLAGS} -Wstrict-prototypes -Wmissing-prototypes -Wimplicit-function-declaration"
|
||||
)
|
||||
|
||||
set (CMAKE_CXX_FLAGS
|
||||
"${COMMON_FLAGS} ${ARCH_FLAGS} -Weffc++"
|
||||
)
|
||||
|
||||
# C preprocessor flags
|
||||
set (CPP_FLAGS
|
||||
" -MD -Wall -Wundef"
|
||||
)
|
||||
|
||||
add_definitions (${CPP_FLAGS})
|
||||
|
||||
# set platform
|
||||
add_definitions (-DSTM32F4)
|
||||
|
||||
set (CMAKE_EXE_LINKER_FLAGS
|
||||
"--static -nostartfiles -T${CMAKE_SOURCE_DIR}/libusbhost_stm32f4.ld -Wl,-Map=FIXME_ONE.map -Wl,--gc-sections -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group"
|
||||
)
|
||||
|
||||
include_directories (${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
function (init_libopencm3)
|
||||
include_directories (${CMAKE_SOURCE_DIR}/libopencm3/include)
|
||||
link_directories (${CMAKE_SOURCE_DIR}/libopencm3/lib)
|
||||
set (LIBOPENCM3_LIB opencm3_stm32f4 PARENT_SCOPE)
|
||||
execute_process (
|
||||
COMMAND sh "${CMAKE_SOURCE_DIR}/initRepo.sh"
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_QUIET
|
||||
)
|
||||
endfunction (init_libopencm3)
|
||||
|
||||
message (STATUS "Initializing repository")
|
||||
init_libopencm3 ()
|
||||
message (STATUS "Repository initialized")
|
||||
|
||||
# Process cached varibles
|
||||
message (STATUS "Setuping build")
|
||||
if (USE_STM32F4_FS)
|
||||
message (STATUS "... Using USB full speed (FS) host periphery")
|
||||
add_definitions (-DUSE_STM32F4_USBH_DRIVER_FS)
|
||||
endif (USE_STM32F4_FS)
|
||||
|
||||
if (USE_STM32F4_HS)
|
||||
message (STATUS "... Using USB high speed (HS) host periphery")
|
||||
add_definitions (-DUSE_STM32F4_USBH_DRIVER_HS)
|
||||
endif (USE_STM32F4_HS)
|
||||
|
||||
if (USE_USART_DEBUG)
|
||||
message (STATUS "... Using debug uart output")
|
||||
add_definitions (-DUSART_DEBUG)
|
||||
endif (USE_USART_DEBUG)
|
||||
message (STATUS "Setup done")
|
||||
|
||||
add_custom_target (README.md
|
||||
SOURCES README.md
|
||||
)
|
||||
|
||||
add_subdirectory (src)
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
TODO
|
||||
|
||||
See usbh_driver*.c in src directory for example of device drivers.
|
||||
2
Doxyfile
2
Doxyfile
|
|
@ -2133,7 +2133,7 @@ HIDE_UNDOC_RELATIONS = YES
|
|||
# set to NO
|
||||
# The default value is: NO.
|
||||
|
||||
HAVE_DOT = NO
|
||||
HAVE_DOT = YES
|
||||
|
||||
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
|
||||
# to run in parallel. When set to 0 doxygen will base this on the number of
|
||||
|
|
|
|||
267
Makefile
267
Makefile
|
|
@ -1,267 +0,0 @@
|
|||
##
|
||||
## This file is part of the libusbhost project.
|
||||
## Imported and adopted from libopencm3 project.
|
||||
##
|
||||
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
|
||||
## Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
|
||||
## Copyright (C) 2013 Frantisek Burian <BuFran@seznam.cz>
|
||||
## Copyright (C) 2014 Amir Hammad <amir.hammad@hotmail.com>
|
||||
##
|
||||
## This library is free software: you can redistribute it and/or modify
|
||||
## it under the terms of the GNU Lesser General Public License as published by
|
||||
## the Free Software Foundation, either version 3 of the License, or
|
||||
## (at your option) any later version.
|
||||
##
|
||||
## This library 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 Lesser General Public License for more details.
|
||||
##
|
||||
## You should have received a copy of the GNU Lesser General Public License
|
||||
## along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
##
|
||||
|
||||
BINARY = demo
|
||||
BINARY := $(addprefix build/, demo)
|
||||
LIBUSBHOSTNAME = usbhost
|
||||
|
||||
LIBUSBHOST := $(addprefix build/lib, $(LIBUSBHOSTNAME))
|
||||
LIBNAME = opencm3_stm32f4
|
||||
DEFS = -DSTM32F4
|
||||
|
||||
# load user config
|
||||
include config.mk
|
||||
DEFS += $(USER_CONFIG)
|
||||
|
||||
ifdef USART_DEBUG
|
||||
DEFS += -DUSART_DEBUG
|
||||
endif
|
||||
|
||||
DEFS += -Iinclude
|
||||
LDSCRIPT = lib$(LIBNAME).ld
|
||||
|
||||
SRCDIR = src
|
||||
OPENCM3_DIR ?= ./libopencm3
|
||||
FP_FLAGS ?= -mfloat-abi=hard -mfpu=fpv4-sp-d16 -mfp16-format=alternative
|
||||
ARCH_FLAGS = -mthumb -mcpu=cortex-m4 $(FP_FLAGS)
|
||||
|
||||
################################################################################
|
||||
# OpenOCD specific variables
|
||||
|
||||
OOCD ?= openocd
|
||||
OOCD_INTERFACE ?= stlink-v2
|
||||
OOCD_BOARD ?= stm32f4discovery
|
||||
|
||||
################################################################################
|
||||
# Black Magic Probe specific variables
|
||||
# Set the BMP_PORT to a serial port and then BMP is used for flashing
|
||||
BMP_PORT ?=
|
||||
|
||||
################################################################################
|
||||
# texane/stlink specific variables
|
||||
#STLINK_PORT ?= :4242
|
||||
|
||||
# Be silent per default, but 'make V=1' will show all compiler calls.
|
||||
ifneq ($(V),1)
|
||||
Q := @
|
||||
NULL := 2>/dev/null
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
# Executables
|
||||
|
||||
PREFIX ?= arm-none-eabi
|
||||
|
||||
CC := $(PREFIX)-gcc
|
||||
CXX := $(PREFIX)-g++
|
||||
LD := $(PREFIX)-gcc
|
||||
AR := $(PREFIX)-ar
|
||||
AS := $(PREFIX)-as
|
||||
OBJCOPY := $(PREFIX)-objcopy
|
||||
OBJDUMP := $(PREFIX)-objdump
|
||||
GDB := $(PREFIX)-gdb
|
||||
STFLASH = $(shell which st-flash)
|
||||
STYLECHECK := /checkpatch.pl
|
||||
STYLECHECKFLAGS := --no-tree -f --terse --mailback
|
||||
STYLECHECKFILES := $(shell find . -name '*.[ch]')
|
||||
|
||||
|
||||
###############################################################################
|
||||
# Source files
|
||||
|
||||
LDSCRIPT ?= $(BINARY).ld
|
||||
|
||||
|
||||
SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.c)))
|
||||
OBJSDEMO := $(patsubst %.c, build/%.o ,$(SRCS))
|
||||
SRCS := $(sort $(notdir $(wildcard $(SRCDIR)/*.cpp)))
|
||||
OBJSDEMO += $(patsubst %.cpp, build/%.o ,$(SRCS))
|
||||
OBJS = $(filter-out $(BINARY).o, $(OBJSDEMO))
|
||||
|
||||
ifndef USART_DEBUG
|
||||
OBJS := $(filter-out build/usart_helpers.o, $(OBJS))
|
||||
OBJSDEMO := $(filter-out build/usart_helpers.o, $(OBJSDEMO))
|
||||
else
|
||||
$(info compiling with DEBUG functions)
|
||||
endif
|
||||
|
||||
|
||||
INCLUDE_DIR = $(OPENCM3_DIR)/include
|
||||
LIB_DIR = $(OPENCM3_DIR)/lib
|
||||
SCRIPT_DIR = $(OPENCM3_DIR)/scripts
|
||||
|
||||
###############################################################################
|
||||
# C flags
|
||||
|
||||
CFLAGS += -Ofast -g
|
||||
CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration
|
||||
CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
|
||||
CFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||
|
||||
###############################################################################
|
||||
# C++ flags
|
||||
|
||||
CXXFLAGS += -Ofast -g
|
||||
CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++
|
||||
CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
|
||||
|
||||
###############################################################################
|
||||
# C & C++ preprocessor common flags
|
||||
|
||||
CPPFLAGS += -MD
|
||||
CPPFLAGS += -Wall -Wundef
|
||||
CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS)
|
||||
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
|
||||
LDFLAGS += --static -nostartfiles
|
||||
LDFLAGS += -L$(LIB_DIR)
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
LDFLAGS += -Wl,-Map=build/$*.map
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
ifeq ($(V),99)
|
||||
LDFLAGS += -Wl,--print-gc-sections
|
||||
endif
|
||||
|
||||
###############################################################################
|
||||
# Used libraries
|
||||
|
||||
LDLIBS += -l$(LIBNAME)
|
||||
LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
|
||||
|
||||
###############################################################################
|
||||
###############################################################################
|
||||
###############################################################################
|
||||
|
||||
.SUFFIXES: .elf .bin .hex .srec .list .map .images
|
||||
.SECONDEXPANSION:
|
||||
.SECONDARY:
|
||||
|
||||
|
||||
all: elf bin lib
|
||||
doc:
|
||||
doxygen
|
||||
|
||||
elf: $(BINARY).elf
|
||||
bin: $(BINARY).bin
|
||||
hex: $(BINARY).hex
|
||||
srec: $(BINARY).srec
|
||||
list: $(BINARY).list
|
||||
lib: $(LIBUSBHOST).a
|
||||
images: $(BINARY).images
|
||||
flash: $(BINARY).flash
|
||||
|
||||
%.images: %.bin %.hex %.srec %.list %.map
|
||||
@#printf "*** $* images generated ***\n"
|
||||
|
||||
%.bin: %.elf
|
||||
@printf " OBJCOPY $(*).bin\n"
|
||||
$(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
|
||||
|
||||
%.hex: %.elf
|
||||
@#printf " OBJCOPY $(*).hex\n"
|
||||
$(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex
|
||||
|
||||
%.srec: %.elf
|
||||
@#printf " OBJCOPY $(*).srec\n"
|
||||
$(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec
|
||||
|
||||
%.list: %.elf
|
||||
@#printf " OBJDUMP $(*).list\n"
|
||||
$(Q)$(OBJDUMP) -S $(*).elf > $(*).list
|
||||
|
||||
-include $(OBJSDEMO:.o=.d)
|
||||
build/%.elf build/%.map: $(OBJSDEMO) $(LDSCRIPT)
|
||||
@printf " LD $(*).elf\n"
|
||||
$(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJSDEMO) $(LDLIBS) -o build/$*.elf
|
||||
|
||||
build/%.o:$(SRCDIR)/%.c
|
||||
@printf " CC $(*).c\n"
|
||||
$(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$*.c
|
||||
|
||||
build/%.o: $(SRCDIR)/%.cxx
|
||||
@printf " CXX $(*).cxx\n"
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$(*).cxx
|
||||
|
||||
build/%.o: $(SRCDIR)/%.cpp
|
||||
@printf " CXX $(*).cpp\n"
|
||||
$(Q)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) -o $@ -c $(SRCDIR)/$(*).cpp
|
||||
$(LIB_DIR)/lib$(LIBNAME).a:
|
||||
|
||||
clean:
|
||||
@#printf " CLEAN\n"
|
||||
@rm -f build/*
|
||||
|
||||
|
||||
%.stlink-flash: %.bin
|
||||
@printf " FLASH $<\n"
|
||||
$(Q)$(STFLASH) write $(*).bin 0x8000000
|
||||
|
||||
ifeq ($(STLINK_PORT),)
|
||||
ifeq ($(BMP_PORT),)
|
||||
ifeq ($(OOCD_SERIAL),)
|
||||
%.flash: %.hex
|
||||
@printf " FLASH $<\n"
|
||||
@# IMPORTANT: Don't use "resume", only "reset" will work correctly!
|
||||
$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
|
||||
-f board/$(OOCD_BOARD).cfg \
|
||||
-c "init" -c "reset init" \
|
||||
-c "flash write_image erase $(*).hex" \
|
||||
-c "reset" \
|
||||
-c "shutdown" $(NULL)
|
||||
else
|
||||
%.flash: %.hex
|
||||
@printf " FLASH $<\n"
|
||||
@# IMPORTANT: Don't use "resume", only "reset" will work correctly!
|
||||
$(Q)$(OOCD) -f interface/$(OOCD_INTERFACE).cfg \
|
||||
-f board/$(OOCD_BOARD).cfg \
|
||||
-c "ft2232_serial $(OOCD_SERIAL)" \
|
||||
-c "init" -c "reset init" \
|
||||
-c "flash write_image erase $(*).hex" \
|
||||
-c "reset" \
|
||||
-c "shutdown" $(NULL)
|
||||
endif
|
||||
else
|
||||
%.flash: %.elf
|
||||
@printf " GDB $(*).elf (flash)\n"
|
||||
$(Q)$(GDB) --batch \
|
||||
-ex 'target extended-remote $(BMP_PORT)' \
|
||||
-x $(SCRIPT_DIR)/black_magic_probe_flash.scr \
|
||||
$(*).elf
|
||||
endif
|
||||
else
|
||||
%.flash: %.elf
|
||||
@printf " GDB $(*).elf (flash)\n"
|
||||
$(Q)$(GDB) --batch \
|
||||
-ex 'target extended-remote $(STLINK_PORT)' \
|
||||
-x $(SCRIPT_DIR)/stlink_flash.scr \
|
||||
$(*).elf
|
||||
endif
|
||||
|
||||
.PHONY: images clean stylecheck styleclean elf bin hex srec list testing doc
|
||||
|
||||
-include $(OBJS:.o=.d)
|
||||
build/lib$(LIBUSBHOSTNAME).a: $(OBJS)
|
||||
@printf " LIB $@\n"
|
||||
$(Q)$(AR) rcs $@ $(OBJS)
|
||||
140
README.md
140
README.md
|
|
@ -1,83 +1,105 @@
|
|||
###General Information
|
||||
[](https://travis-ci.org/libusbhost/libusbhost)
|
||||
##General Information
|
||||
|
||||
[Link to the official repository](http://github.com/libusbhost/libusbhost)
|
||||
|
||||
**This library is in an active development.**
|
||||
**WARNING**: None of its features are considered stable !
|
||||
###Objectives
|
||||
|
||||
This library implement usb host driver allowing users use
|
||||
or write device drivers, which functionality
|
||||
is abstracted of low level implementation.
|
||||
|
||||
Main objectives are:
|
||||
- provide open-source(Lesser GPL3) usb host library for embedded devices
|
||||
- execution speed: This library doesn't use blocking sleep,
|
||||
- execution speed. This library doesn't use blocking sleep,
|
||||
making low overhead on runtime performance
|
||||
- uses static allocation for all its buffers,
|
||||
so no allocation and reallocation is affecting performance
|
||||
(possibility of memory fragmentation. execution time indeterminism),
|
||||
so no malloc(), realloc(), free().
|
||||
- written in C, with the support to use it with C++.
|
||||
- does not depend on any Operating System. Library libopencm3 is used for testing purposes and to get proper defines.
|
||||
So no runtime dependency is on this library.
|
||||
- use static allocation for all of its buffers.
|
||||
This means no allocation and reallocation is affecting performance
|
||||
(possibility of memory fragmentation. execution time indeterminism). No malloc(), realloc(), free()
|
||||
- do not depend on any operating system
|
||||
|
||||
### Supported hardware
|
||||
|
||||
- stm32f4discovery
|
||||
|
||||
Currently supported devices (yet tested) are:
|
||||
* stm32f407 (stm32f4 Discovery)
|
||||
### Supported device drivers
|
||||
|
||||
Native device drivers (mostly for demonstration purposes):
|
||||
- HUB
|
||||
- Gamepad - XBox compatible Controller
|
||||
- mouse (draft: only displays raw data)
|
||||
- Generic Human Interface driver: mouse, keyboard (raw data)
|
||||
- USB MIDI devices (raw data + note on/off)
|
||||
|
||||
###Practical info
|
||||
## Steps to compile library and demo
|
||||
### Prerequisities
|
||||
Make sure the following prerequisities are installed to be able to compile this library
|
||||
- **git** for libopencm3 submodule fetch
|
||||
- **gcc-arm-none-eabi** toolchain for cross compilation
|
||||
- **cmake**
|
||||
- **ccmake** (optional)
|
||||
- **openocd** (optional)
|
||||
|
||||
!!! Do not forget to invoke "make clean" before new build when defines change(_TODO: remove this warning and fix the Makefile_)
|
||||
### Basic setup
|
||||
1. go to build directory located in the root of the project
|
||||
> cd build
|
||||
|
||||
2. compile demo and the library with the default options set
|
||||
> cmake .. && make
|
||||
|
||||
**How to initialize repository**
|
||||
Executable demo is placed into `build/demo.hex`.
|
||||
Library is placed into `build/src/libusbhost.a`.
|
||||
|
||||
> ./initRepo.sh
|
||||
### Advanced setup
|
||||
*cmake* initial cache variables
|
||||
<table>
|
||||
<tr>
|
||||
<th>Cache variable</th><th>Value</th><th>Description</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>USE_STM32F4_FS</td><td>TRUE</td><td>Enable STM32F4 Full Speed USB host peripheral</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>USE_STM32F4_HS</td><td>TRUE</td><td>Enable STM32F4 High Speed USB host peripheral</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>USE_USART_DEBUG</td><td>TRUE</td><td>Enable writing of the debug information to USART6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OOCD_INTERFACE</td><td>"stlink-v2"</td><td>Interface configuration file used by the openocd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>OOCD_BOARD</td><td>"stm32f4discovery"</td><td>Board configuration file used by the openocd</td>
|
||||
</tr>
|
||||
</table>
|
||||
You can alter these by issuing the following commands in the build directory
|
||||
|
||||
fetch libopencm3 submodule and compile needed libraries
|
||||
- Graphical user interface
|
||||
> ccmake ..
|
||||
|
||||
**How to generate documentation**
|
||||
- Command line interface
|
||||
> cmake .. -D{VARIABLE}={VALUE}
|
||||
|
||||
> make doc
|
||||
### Flashing
|
||||
If the *openocd* is installed, `make flash` executed in the build directory
|
||||
flashes the `build/demo.hex` to the stm32f4discovery board.
|
||||
|
||||
**How to compile demo**
|
||||
### Reading debug output
|
||||
The following table represents the configuration of the debug output
|
||||
<table>
|
||||
<tr>
|
||||
<th>GPIO</th><td>GPIOC6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>USART periphery</th><td>USART6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Function</th><td>UART TX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Baud rate</th><td>921600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Uart mode</th><td>8N1</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Edit usbh_config.h to configure the library (By default Full speed OTG periphery on stm32f4 is supported)
|
||||
## License
|
||||
|
||||
The libusbhost code is released under the terms of the GNU Lesser General
|
||||
Public License (LGPL), version 3 or later.
|
||||
|
||||
> ./compileDemo.sh
|
||||
|
||||
compiles demo, that can be flashed into stm32f4 Discovery platform and debug by USART
|
||||
|
||||
|
||||
**How to upload firmware (FLASH) to stm32f4 Discovery**
|
||||
|
||||
> sudo make flash
|
||||
|
||||
|
||||
**How to view debug data**
|
||||
|
||||
connect uart to USART6 pins on gpios: GPIOC6(TX - data), GPIOC7(RX - not used)
|
||||
configure uart baud on PC side to 921600 with 1 stop bit, no parity, 8bit data, no handshake
|
||||
|
||||
|
||||
**How to compile library only**
|
||||
|
||||
> make lib
|
||||
|
||||
**libusbhost.a** is built without usart debug support
|
||||
(check compileDemo.sh for hint on how to compile with debug)
|
||||
|
||||
|
||||
###Contact
|
||||
Amir Hammad - *amir.hammad@hotmail.com*
|
||||
|
||||
**Library is maintained there**
|
||||
> http://github.com/libusbhost/libusbhost
|
||||
|
||||
See COPYING.GPL3 and COPYING.LGPL3 for details.
|
||||
|
|
|
|||
1
build/.gitignore
vendored
1
build/.gitignore
vendored
|
|
@ -0,0 +1 @@
|
|||
*
|
||||
6
cmake/doc.cmake
Normal file
6
cmake/doc.cmake
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
add_custom_target (doc
|
||||
COMMAND doxygen
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
COMMENT "output is generted in the ${CMAKE_SOURCE_DIR}/doc"
|
||||
SOURCES Doxyfile
|
||||
)
|
||||
18
cmake/openocd_flash.cmake
Normal file
18
cmake/openocd_flash.cmake
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
find_program (OOCD openocd DOC "openocd executable")
|
||||
|
||||
set (OOCD_INTERFACE stlink-v2 CACHE STRING "interface config file used for openocd flashing")
|
||||
set (OOCD_BOARD stm32f4discovery CACHE STRING "board config file used for openocd flashing")
|
||||
if (OOCD)
|
||||
message (STATUS "OpenOCD found: ${OOCD}")
|
||||
message (STATUS "... interface: ${OOCD_INTERFACE}")
|
||||
message (STATUS "... board: ${OOCD_BOARD}")
|
||||
add_custom_target (flash
|
||||
COMMAND sh -c '${OOCD} -f interface/${OOCD_INTERFACE}.cfg
|
||||
-f board/${OOCD_BOARD}.cfg
|
||||
-c "init" -c "reset init"
|
||||
-c "flash write_image erase $<TARGET_FILE:demo>"
|
||||
-c "reset"
|
||||
-c "shutdown" '
|
||||
DEPENDS demo
|
||||
)
|
||||
endif (OOCD)
|
||||
15
cmake/toolchain.cmake
Normal file
15
cmake/toolchain.cmake
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
set (_CMAKE_TOOLCHAIN_PREFIX "arm-none-eabi-" CACHE STRING "toolchain prefix")
|
||||
set (_CMAKE_TOOLCHAIN_LOCATION "" CACHE STRING "toolchain location hint")
|
||||
|
||||
set (CMAKE_SYSTEM_NAME Generic)
|
||||
set (CMAKE_C_COMPILER_WORKS 1)
|
||||
set (CMAKE_CXX_COMPILER_WORKS 1)
|
||||
set (CMAKE_C_FLAGS "")
|
||||
set (CMAKE_CXX_FLAGS "")
|
||||
set (BUILD_SHARED_LIBS OFF)
|
||||
find_program (CMAKE_C_COMPILER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}gcc HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
|
||||
find_program (CMAKE_C_COMPILER NAMES ${_CMAKE_TOOLCHAIN_PREFIX}g++ HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
|
||||
find_program (CMAKE_OBJCOPY NAMES ${_CMAKE_TOOLCHAIN_PREFIX}objcopy HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
|
||||
find_program (CMAKE_SIZE NAMES ${_CMAKE_TOOLCHAIN_PREFIX}size HINTS ${_CMAKE_TOOLCHAIN_LOCATION})
|
||||
|
||||
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
#!/bin/sh
|
||||
USART_DEBUG=1 OPENCM3_DIR=libopencm3 make all
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
|
||||
|
||||
USER_CONFIG =
|
||||
|
||||
|
|
@ -26,6 +26,7 @@
|
|||
#include "usbh_config.h"
|
||||
#include "usbh_core.h"
|
||||
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
BEGIN_DECLS
|
||||
|
|
@ -61,6 +62,54 @@ enum USBH_CONTROL_TYPE {
|
|||
USBH_CONTROL_TYPE_DATA
|
||||
};
|
||||
|
||||
enum USBH_ENUM_STATE {
|
||||
USBH_ENUM_STATE_SET_ADDRESS,
|
||||
USBH_ENUM_STATE_FIRST = USBH_ENUM_STATE_SET_ADDRESS,
|
||||
USBH_ENUM_STATE_DEVICE_DT_READ_SETUP,
|
||||
USBH_ENUM_STATE_DEVICE_DT_READ_COMPLETE,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_SETUP,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_COMPLETE,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_READ_SETUP,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_READ,
|
||||
USBH_ENUM_STATE_CONFIGURATION_DT_READ_COMPLETE,
|
||||
USBH_ENUM_STATE_SET_CONFIGURATION_SETUP,
|
||||
USBH_ENUM_STATE_SET_CONFIGURATION_COMPLETE,
|
||||
USBH_ENUM_STATE_FIND_DRIVER,
|
||||
};
|
||||
|
||||
enum USBH_CONTROL_STATE {
|
||||
USBH_CONTROL_STATE_NONE,
|
||||
USBH_CONTROL_STATE_SETUP,
|
||||
USBH_CONTROL_STATE_DATA,
|
||||
USBH_CONTROL_STATE_STATUS,
|
||||
};
|
||||
|
||||
typedef struct _usbh_device usbh_device_t;
|
||||
|
||||
struct _usbh_packet_callback_data {
|
||||
/// status - it is used for reporting of the errors
|
||||
enum USBH_PACKET_CALLBACK_STATUS status;
|
||||
|
||||
/// count of bytes that has been actually transferred
|
||||
uint32_t transferred_length;
|
||||
};
|
||||
typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
|
||||
|
||||
typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
|
||||
|
||||
struct _usbh_control {
|
||||
enum USBH_CONTROL_STATE state;
|
||||
usbh_packet_callback_t callback;
|
||||
union {
|
||||
const void *out;
|
||||
void *in;
|
||||
} data;
|
||||
uint16_t data_length;
|
||||
struct usb_setup_data setup_data;
|
||||
};
|
||||
typedef struct _usbh_control usbh_control_t;
|
||||
|
||||
/**
|
||||
* @brief The _usbh_device struct
|
||||
*
|
||||
|
|
@ -77,7 +126,8 @@ struct _usbh_device {
|
|||
enum USBH_SPEED speed;
|
||||
|
||||
/// state used for enumeration purposes
|
||||
uint8_t state;
|
||||
enum USBH_ENUM_STATE state;
|
||||
usbh_control_t control;
|
||||
|
||||
/// toggle bit
|
||||
uint8_t toggle0;
|
||||
|
|
@ -99,20 +149,12 @@ struct _usbh_device {
|
|||
};
|
||||
typedef struct _usbh_device usbh_device_t;
|
||||
|
||||
struct _usbh_packet_callback_data {
|
||||
/// status - it is used for reporting of the errors
|
||||
enum USBH_PACKET_CALLBACK_STATUS status;
|
||||
|
||||
/// count of bytes that has been actually transferred
|
||||
uint32_t transferred_length;
|
||||
};
|
||||
typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
|
||||
|
||||
typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
|
||||
|
||||
struct _usbh_packet {
|
||||
/// pointer to data
|
||||
void *data;
|
||||
union {
|
||||
const void *out;
|
||||
void *in;
|
||||
} data;
|
||||
|
||||
/// length of the data (up to 1023)
|
||||
uint16_t datalen;
|
||||
|
|
@ -201,6 +243,66 @@ struct _usbh_generic_data {
|
|||
typedef struct _usbh_generic_data usbh_generic_data_t;
|
||||
|
||||
|
||||
/// set to -1 for unused items ("don't care" functionality) @see find_driver()
|
||||
struct _usbh_dev_driver_info {
|
||||
int32_t deviceClass;
|
||||
int32_t deviceSubClass;
|
||||
int32_t deviceProtocol;
|
||||
int32_t idVendor;
|
||||
int32_t idProduct;
|
||||
int32_t ifaceClass;
|
||||
int32_t ifaceSubClass;
|
||||
int32_t ifaceProtocol;
|
||||
};
|
||||
typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t;
|
||||
|
||||
struct _usbh_dev_driver {
|
||||
/**
|
||||
* @brief init is initialization routine of the device driver
|
||||
*
|
||||
* This function is called during the initialization of the device driver
|
||||
*/
|
||||
void *(*init)(usbh_device_t *usbh_dev);
|
||||
|
||||
/**
|
||||
* @brief analyze descriptor
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
* @param[in] descriptor is the pointer to the descriptor that should
|
||||
* be parsed in order to prepare driver to be loaded
|
||||
*
|
||||
* @retval true when the enumeration is complete and the driver is ready to be used
|
||||
* @retval false when the device driver is not ready to be used
|
||||
*
|
||||
* This should be used for getting correct endpoint numbers, getting maximum sizes of endpoints.
|
||||
* Should return true, when no more data is needed.
|
||||
*
|
||||
*/
|
||||
bool (*analyze_descriptor)(void *drvdata, void *descriptor);
|
||||
|
||||
/**
|
||||
* @brief poll method is called periodically by the library core
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
* @param[in] time_curr_us current timestamp in microseconds
|
||||
* @see usbh_poll()
|
||||
*/
|
||||
void (*poll)(void *drvdata, uint32_t time_curr_us);
|
||||
|
||||
/**
|
||||
* @brief unloads the device driver
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
*
|
||||
* This should free any data associated with this device
|
||||
*/
|
||||
void (*remove)(void *drvdata);
|
||||
|
||||
/**
|
||||
* @brief info - compatibility information about the driver. It is used by the core during device enumeration
|
||||
* @see find_driver()
|
||||
*/
|
||||
const usbh_dev_driver_info_t * const info;
|
||||
};
|
||||
typedef struct _usbh_dev_driver usbh_dev_driver_t;
|
||||
|
||||
#define ERROR(arg) LOG_PRINTF("UNHANDLED_ERROR %d: file: %s, line: %d",\
|
||||
arg, __FILE__, __LINE__)
|
||||
|
||||
|
|
@ -216,10 +318,8 @@ void usbh_read(usbh_device_t *dev, usbh_packet_t *packet);
|
|||
void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet);
|
||||
|
||||
/* Helper functions used by device drivers */
|
||||
void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
void device_xfer_control_write_setup(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
void device_xfer_control_write_data(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
|
||||
|
||||
void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data);
|
||||
void device_remove(usbh_device_t *dev);
|
||||
|
||||
END_DECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@
|
|||
// Set this wisely
|
||||
#define BUFFER_ONE_BYTES (2048)
|
||||
|
||||
// MOUSE
|
||||
#define USBH_HID_MOUSE_MAX_DEVICES (2)
|
||||
|
||||
#define USBH_HID_MOUSE_BUFFER (32)
|
||||
// HID class devices
|
||||
#define USBH_HID_MAX_DEVICES (2)
|
||||
#define USBH_HID_BUFFER (256)
|
||||
#define USBH_HID_REPORT_BUFFER (4)
|
||||
|
||||
// MIDI
|
||||
// Maximal number of midi devices connected to whatever hub
|
||||
|
|
@ -59,10 +59,4 @@
|
|||
#error USBH_MAX_DEVICES > 127
|
||||
#endif
|
||||
|
||||
// Uncomment to enable OTG_HS support - low level driver
|
||||
// #define USE_STM32F4_USBH_DRIVER_HS
|
||||
|
||||
// Uncomment to enable OTG_FS support - low level driver
|
||||
#define USE_STM32F4_USBH_DRIVER_FS
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -40,72 +40,15 @@
|
|||
|
||||
BEGIN_DECLS
|
||||
|
||||
/// set to -1 for unused items ("don't care" functionality) @see find_driver()
|
||||
struct _usbh_dev_driver_info {
|
||||
int32_t deviceClass;
|
||||
int32_t deviceSubClass;
|
||||
int32_t deviceProtocol;
|
||||
int32_t idVendor;
|
||||
int32_t idProduct;
|
||||
int32_t ifaceClass;
|
||||
int32_t ifaceSubClass;
|
||||
int32_t ifaceProtocol;
|
||||
};
|
||||
typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t;
|
||||
|
||||
struct _usbh_dev_driver {
|
||||
/**
|
||||
* @brief init is initialization routine of the device driver
|
||||
*
|
||||
* This function is called during the initialization of the device driver
|
||||
*/
|
||||
void *(*init)(void *usbh_dev);
|
||||
|
||||
/**
|
||||
* @brief analyze descriptor
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
* @param[in] descriptor is the pointer to the descriptor that should
|
||||
* be parsed in order to prepare driver to be loaded
|
||||
*
|
||||
* @retval true when the enumeration is complete and the driver is ready to be used
|
||||
* @retval false when the device driver is not ready to be used
|
||||
*
|
||||
* This should be used for getting correct endpoint numbers, getting maximum sizes of endpoints.
|
||||
* Should return true, when no more data is needed.
|
||||
*
|
||||
*/
|
||||
bool (*analyze_descriptor)(void *drvdata, void *descriptor);
|
||||
|
||||
/**
|
||||
* @brief poll method is called periodically by the library core
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
* @param[in] time_curr_us current timestamp in microseconds
|
||||
* @see usbh_poll()
|
||||
*/
|
||||
void (*poll)(void *drvdata, uint32_t time_curr_us);
|
||||
|
||||
/**
|
||||
* @brief unloads the device driver
|
||||
* @param[in/out] drvdata is the device driver's private data
|
||||
*
|
||||
* This should free any data associated with this device
|
||||
*/
|
||||
void (*remove)(void *drvdata);
|
||||
|
||||
/**
|
||||
* @brief info - compatibility information about the driver. It is used by the core during device enumeration
|
||||
* @see find_driver()
|
||||
*/
|
||||
const usbh_dev_driver_info_t * const info;
|
||||
};
|
||||
typedef struct _usbh_dev_driver usbh_dev_driver_t;
|
||||
typedef struct _usbh_low_level_driver usbh_low_level_driver_t;
|
||||
|
||||
/**
|
||||
* @brief usbh_init
|
||||
* @param low_level_drivers list of the low level drivers to be used by this library
|
||||
* @param device_drivers list of the device drivers that could be used with attached devices
|
||||
*/
|
||||
void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]);
|
||||
void usbh_init(const usbh_low_level_driver_t * const low_level_drivers[], const usbh_dev_driver_t * const device_drivers[]);
|
||||
|
||||
/**
|
||||
* @brief usbh_poll
|
||||
|
|
|
|||
85
include/usbh_driver_hid.h
Normal file
85
include/usbh_driver_hid.h
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* This file is part of the libusbhost library
|
||||
* hosted at http://github.com/libusbhost/libusbhost
|
||||
*
|
||||
* Copyright (C) 2016 Amir Hammad <amir.hammad@hotmail.com>
|
||||
*
|
||||
*
|
||||
* libusbhost is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USBH_DRIVER_HID_
|
||||
#define USBH_DRIVER_HID_
|
||||
|
||||
#include "usbh_core.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
BEGIN_DECLS
|
||||
|
||||
struct _hid_mouse_config {
|
||||
/**
|
||||
* @brief this is called when some data is read when polling the device
|
||||
* @param device_id handle of HID device
|
||||
* @param data pointer to the data
|
||||
* @param length count of bytes in the data
|
||||
*
|
||||
* TODO: make better interface that provides data contained in the report descriptor
|
||||
*
|
||||
*/
|
||||
void (*hid_in_message_handler)(uint8_t device_id, const uint8_t *data, uint32_t length);
|
||||
};
|
||||
typedef struct _hid_mouse_config hid_config_t;
|
||||
|
||||
/**
|
||||
* @brief hid_mouse_driver_init initialization routine - this will initialize internal structures of this device driver
|
||||
* @param config
|
||||
* @see hid_mouse_config_t
|
||||
*/
|
||||
void hid_driver_init(const hid_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief hid_set_report
|
||||
* @param device_id handle of HID device
|
||||
* @returns true on success, false otherwise
|
||||
*/
|
||||
bool hid_set_report(uint8_t device_id, uint8_t val);
|
||||
|
||||
enum HID_TYPE {
|
||||
HID_TYPE_NONE,
|
||||
HID_TYPE_MOUSE,
|
||||
HID_TYPE_KEYBOARD,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief hid_get_type
|
||||
* @param device_id handle of HID device
|
||||
* @return type of attached HID
|
||||
* @see enum HID_TYPE
|
||||
*/
|
||||
enum HID_TYPE hid_get_type(uint8_t device_id);
|
||||
|
||||
/**
|
||||
* @brief hid_is_connected
|
||||
* @param device_id handle of HID device
|
||||
* @return true if the device with device_id is connected
|
||||
*/
|
||||
bool hid_is_connected(uint8_t device_id);
|
||||
|
||||
extern const usbh_dev_driver_t usbh_hid_driver;
|
||||
|
||||
END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* This file is part of the libusbhost library
|
||||
* hosted at http://github.com/libusbhost/libusbhost
|
||||
*
|
||||
* Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
|
||||
*
|
||||
*
|
||||
* libusbhost is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USBH_DRIVER_HID_MOUSE_
|
||||
#define USBH_DRIVER_HID_MOUSE_
|
||||
|
||||
#include "usbh_core.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
BEGIN_DECLS
|
||||
|
||||
struct _hid_mouse_config {
|
||||
/**
|
||||
* @brief this is called when some data is read when polling the device
|
||||
* @param device_id
|
||||
* @param data pointer to the data (only 4 bytes are valid!)
|
||||
*/
|
||||
void (*mouse_in_message_handler)(uint8_t device_id, const uint8_t *data);
|
||||
};
|
||||
typedef struct _hid_mouse_config hid_mouse_config_t;
|
||||
|
||||
/**
|
||||
* @brief hid_mouse_driver_init initialization routine - this will initialize internal structures of this device driver
|
||||
* @param config
|
||||
* @see hid_mouse_config_t
|
||||
*/
|
||||
void hid_mouse_driver_init(const hid_mouse_config_t *config);
|
||||
|
||||
extern const usbh_dev_driver_t usbh_hid_mouse_driver;
|
||||
|
||||
END_DECLS
|
||||
|
||||
#endif
|
||||
|
|
@ -30,8 +30,8 @@
|
|||
BEGIN_DECLS
|
||||
|
||||
// pass this to usbh init
|
||||
extern const void *usbh_lld_stm32f4_driver_fs;
|
||||
extern const void *usbh_lld_stm32f4_driver_hs;
|
||||
extern const usbh_low_level_driver_t usbh_lld_stm32f4_driver_fs;
|
||||
extern const usbh_low_level_driver_t usbh_lld_stm32f4_driver_hs;
|
||||
|
||||
#ifdef USART_DEBUG
|
||||
void print_channels(const void *drvdata);
|
||||
|
|
|
|||
|
|
@ -28,5 +28,5 @@ MEMORY
|
|||
}
|
||||
|
||||
/* Include the common ld script. */
|
||||
INCLUDE ./libopencm3/lib/libopencm3_stm32f4.ld
|
||||
INCLUDE libopencm3_stm32f4.ld
|
||||
|
||||
61
src/CMakeLists.txt
Normal file
61
src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
if (USE_USART_DEBUG)
|
||||
set (USART_HELPERS
|
||||
usart_helpers.c
|
||||
tinyprintf.c
|
||||
)
|
||||
else (USE_USART_DEBUG)
|
||||
set (USART_HELPERS "")
|
||||
endif (USE_USART_DEBUG)
|
||||
|
||||
set (inc ${CMAKE_SOURCE_DIR}/include)
|
||||
|
||||
add_library (usbhost
|
||||
${USART_HELPERS}
|
||||
${inc}/usbh_core.h
|
||||
${inc}/usbh_driver_ac_midi.h
|
||||
${inc}/usbh_driver_gp_xbox.h
|
||||
${inc}/usbh_driver_hid.h
|
||||
${inc}/usbh_driver_hub.h
|
||||
${inc}/usbh_lld_stm32f4.h
|
||||
${inc}/driver/usbh_device_driver.h
|
||||
|
||||
usbh_core.c
|
||||
usbh_driver_ac_midi.c
|
||||
usbh_driver_ac_midi_private.h
|
||||
usbh_driver_gp_xbox.c
|
||||
usbh_driver_hid.c
|
||||
usbh_driver_hub.c
|
||||
usbh_driver_hub_private.h
|
||||
usbh_lld_stm32f4.c
|
||||
)
|
||||
|
||||
target_link_libraries (usbhost
|
||||
${LIBOPENCM3_LIB}
|
||||
)
|
||||
|
||||
add_executable (demo
|
||||
demo.c
|
||||
)
|
||||
|
||||
target_link_libraries (demo
|
||||
usbhost
|
||||
)
|
||||
|
||||
add_custom_command (TARGET demo
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:demo> ${CMAKE_BINARY_DIR}/demo.hex
|
||||
COMMENT "Generating output files: ${CMAKE_BINARY_DIR}/demo.hex"
|
||||
)
|
||||
|
||||
add_custom_command (TARGET demo
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_SIZE} $<TARGET_FILE:demo>
|
||||
COMMENT "Calculating size of the binary"
|
||||
)
|
||||
|
||||
add_custom_command (TARGET usbhost
|
||||
POST_BUILD
|
||||
COMMENT "Calculating size of the library"
|
||||
COMMAND ${CMAKE_SIZE} $<TARGET_FILE:usbhost>
|
||||
)
|
||||
|
||||
45
src/demo.c
45
src/demo.c
|
|
@ -23,7 +23,7 @@
|
|||
#include "usart_helpers.h" /// provides LOG_PRINTF macros used for debugging
|
||||
#include "usbh_core.h" /// provides usbh_init() and usbh_poll()
|
||||
#include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform
|
||||
#include "usbh_driver_hid_mouse.h" /// provides usb device driver Human Interface Device - type mouse
|
||||
#include "usbh_driver_hid.h" /// provides generic usb device driver for Human Interface Device (HID)
|
||||
#include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported)
|
||||
#include "usbh_driver_gp_xbox.h" /// provides usb device driver for Gamepad: Microsoft XBOX compatible Controller
|
||||
#include "usbh_driver_ac_midi.h" /// provides usb device driver for midi class devices
|
||||
|
|
@ -116,12 +116,23 @@ static void gpio_setup(void)
|
|||
|
||||
static const usbh_dev_driver_t *device_drivers[] = {
|
||||
&usbh_hub_driver,
|
||||
&usbh_hid_mouse_driver,
|
||||
&usbh_hid_driver,
|
||||
&usbh_gp_xbox_driver,
|
||||
&usbh_midi_driver,
|
||||
0
|
||||
NULL
|
||||
};
|
||||
|
||||
static const usbh_low_level_driver_t * const lld_drivers[] = {
|
||||
#ifdef USE_STM32F4_USBH_DRIVER_FS
|
||||
&usbh_lld_stm32f4_driver_fs, // Make sure USE_STM32F4_USBH_DRIVER_FS is defined in usbh_config.h
|
||||
#endif
|
||||
|
||||
#ifdef USE_STM32F4_USBH_DRIVER_HS
|
||||
&usbh_lld_stm32f4_driver_hs, // Make sure USE_STM32F4_USBH_DRIVER_HS is defined in usbh_config.h
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
static void gp_xbox_update(uint8_t device_id, gp_xbox_packet_t packet)
|
||||
{
|
||||
(void)device_id;
|
||||
|
|
@ -148,17 +159,29 @@ static const gp_xbox_config_t gp_xbox_config = {
|
|||
.notify_disconnected = &gp_xbox_disconnected
|
||||
};
|
||||
|
||||
static void mouse_in_message_handler(uint8_t device_id, const uint8_t *data)
|
||||
static void hid_in_message_handler(uint8_t device_id, const uint8_t *data, uint32_t length)
|
||||
{
|
||||
(void)device_id;
|
||||
(void)data;
|
||||
if (length < 4) {
|
||||
LOG_PRINTF("data too short, type=%d\n", hid_get_type(device_id));
|
||||
return;
|
||||
}
|
||||
|
||||
// print only first 4 bytes, since every mouse should have at least these four set.
|
||||
// Report descriptors are not read by driver for now, so we do not know what each byte means
|
||||
LOG_PRINTF("MOUSE EVENT %02X %02X %02X %02X \n", data[0], data[1], data[2], data[3]);
|
||||
LOG_PRINTF("HID EVENT %02X %02X %02X %02X \n", data[0], data[1], data[2], data[3]);
|
||||
if (hid_get_type(device_id) == HID_TYPE_KEYBOARD) {
|
||||
static int x = 0;
|
||||
if (x != data[2]) {
|
||||
x = data[2];
|
||||
hid_set_report(device_id, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const hid_mouse_config_t mouse_config = {
|
||||
.mouse_in_message_handler = &mouse_in_message_handler
|
||||
static const hid_config_t hid_config = {
|
||||
.hid_in_message_handler = &hid_in_message_handler
|
||||
};
|
||||
|
||||
static void midi_in_message_handler(int device_id, uint8_t *data)
|
||||
|
|
@ -200,13 +223,12 @@ int main(void)
|
|||
*
|
||||
* Pass configuration struct where the callbacks are defined
|
||||
*/
|
||||
hid_mouse_driver_init(&mouse_config);
|
||||
hid_driver_init(&hid_config);
|
||||
hub_driver_init();
|
||||
gp_xbox_driver_init(&gp_xbox_config);
|
||||
midi_driver_init(&midi_config);
|
||||
|
||||
gpio_set(GPIOD, GPIO13);
|
||||
|
||||
/**
|
||||
* Pass array of supported low level drivers
|
||||
* In case of stm32f407, there are up to two supported OTG hosts on one chip.
|
||||
|
|
@ -214,11 +236,6 @@ int main(void)
|
|||
*
|
||||
* Pass array of supported device drivers
|
||||
*/
|
||||
const void *lld_drivers[] = {
|
||||
usbh_lld_stm32f4_driver_fs, // Make sure USE_STM32F4_USBH_DRIVER_FS is defined in usbh_config.h
|
||||
// usbh_lld_stm32f4_driver_hs, // Make sure USE_STM32F4_USBH_DRIVER_HS is defined in usbh_config.h
|
||||
0
|
||||
};
|
||||
usbh_init(lld_drivers, device_drivers);
|
||||
gpio_clear(GPIOD, GPIO13);
|
||||
|
||||
|
|
|
|||
521
src/tinyprintf.c
Normal file
521
src/tinyprintf.c
Normal file
|
|
@ -0,0 +1,521 @@
|
|||
/*
|
||||
File: tinyprintf.c
|
||||
|
||||
Copyright (C) 2004 Kustaa Nyholm
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "tinyprintf.h"
|
||||
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
|
||||
/* Enable long int support */
|
||||
#define PRINTF_LONG_SUPPORT
|
||||
|
||||
/* Enable long long int support (implies long int support) */
|
||||
#define PRINTF_LONG_LONG_SUPPORT
|
||||
|
||||
/* Enable %z (size_t) support */
|
||||
#define PRINTF_SIZE_T_SUPPORT
|
||||
|
||||
/*
|
||||
* Configuration adjustments
|
||||
*/
|
||||
#ifdef PRINTF_SIZE_T_SUPPORT
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
# define PRINTF_LONG_SUPPORT
|
||||
#endif
|
||||
|
||||
/* __SIZEOF_<type>__ defined at least by gcc */
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
# define SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
#endif
|
||||
#ifdef __SIZEOF_LONG_LONG__
|
||||
# define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
|
||||
#endif
|
||||
#ifdef __SIZEOF_LONG__
|
||||
# define SIZEOF_LONG __SIZEOF_LONG__
|
||||
#endif
|
||||
#ifdef __SIZEOF_INT__
|
||||
# define SIZEOF_INT __SIZEOF_INT__
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
|
||||
#else
|
||||
# define _TFP_GCC_NO_INLINE_
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Implementation
|
||||
*/
|
||||
struct param {
|
||||
char lz:1; /**< Leading zeros */
|
||||
char alt:1; /**< alternate form */
|
||||
char uc:1; /**< Upper case (for base16 only) */
|
||||
char align_left:1; /**< 0 == align right (default), 1 == align left */
|
||||
unsigned int width; /**< field width */
|
||||
char sign; /**< The sign to display (if any) */
|
||||
unsigned int base; /**< number base (e.g.: 8, 10, 16) */
|
||||
char *bf; /**< Buffer to output */
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
static void _TFP_GCC_NO_INLINE_ ulli2a(
|
||||
unsigned long long int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned long long int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void lli2a(long long int num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
ulli2a(num, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
static void uli2a(unsigned long int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned long int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void li2a(long num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
uli2a(num, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ui2a(unsigned int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void i2a(int num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
ui2a(num, p);
|
||||
}
|
||||
|
||||
static int a2d(char ch)
|
||||
{
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char a2u(char ch, const char **src, int base, unsigned int *nump)
|
||||
{
|
||||
const char *p = *src;
|
||||
unsigned int num = 0;
|
||||
int digit;
|
||||
while ((digit = a2d(ch)) >= 0) {
|
||||
if (digit > base)
|
||||
break;
|
||||
num = num * base + digit;
|
||||
ch = *p++;
|
||||
}
|
||||
*src = p;
|
||||
*nump = num;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void putchw(void *putp, putcf putf, struct param *p)
|
||||
{
|
||||
char ch;
|
||||
int n = p->width;
|
||||
char *bf = p->bf;
|
||||
|
||||
/* Number of filling characters */
|
||||
while (*bf++ && n > 0)
|
||||
n--;
|
||||
if (p->sign)
|
||||
n--;
|
||||
if (p->alt && p->base == 16)
|
||||
n -= 2;
|
||||
else if (p->alt && p->base == 8)
|
||||
n--;
|
||||
|
||||
/* Fill with space to align to the right, before alternate or sign */
|
||||
if (!p->lz && !p->align_left) {
|
||||
while (n-- > 0)
|
||||
putf(putp, ' ');
|
||||
}
|
||||
|
||||
/* print sign */
|
||||
if (p->sign)
|
||||
putf(putp, p->sign);
|
||||
|
||||
/* Alternate */
|
||||
if (p->alt && p->base == 16) {
|
||||
putf(putp, '0');
|
||||
putf(putp, (p->uc ? 'X' : 'x'));
|
||||
} else if (p->alt && p->base == 8) {
|
||||
putf(putp, '0');
|
||||
}
|
||||
|
||||
/* Fill with zeros, after alternate or sign */
|
||||
if (p->lz) {
|
||||
while (n-- > 0)
|
||||
putf(putp, '0');
|
||||
}
|
||||
|
||||
/* Put actual buffer */
|
||||
bf = p->bf;
|
||||
while ((ch = *bf++))
|
||||
putf(putp, ch);
|
||||
|
||||
/* Fill with space to align to the left, after string */
|
||||
if (!p->lz && p->align_left) {
|
||||
while (n-- > 0)
|
||||
putf(putp, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
|
||||
{
|
||||
struct param p;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
char bf[23]; /* long = 64b on some architectures */
|
||||
#else
|
||||
char bf[12]; /* int = 32b on some architectures */
|
||||
#endif
|
||||
char ch;
|
||||
p.bf = bf;
|
||||
|
||||
while ((ch = *(fmt++))) {
|
||||
if (ch != '%') {
|
||||
putf(putp, ch);
|
||||
} else {
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
char lng = 0; /* 1 for long, 2 for long long */
|
||||
#endif
|
||||
/* Init parameter struct */
|
||||
p.lz = 0;
|
||||
p.alt = 0;
|
||||
p.width = 0;
|
||||
p.align_left = 0;
|
||||
p.sign = 0;
|
||||
|
||||
/* Flags */
|
||||
while ((ch = *(fmt++))) {
|
||||
switch (ch) {
|
||||
case '-':
|
||||
p.align_left = 1;
|
||||
continue;
|
||||
case '0':
|
||||
p.lz = 1;
|
||||
continue;
|
||||
case '#':
|
||||
p.alt = 1;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Width */
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
ch = a2u(ch, &fmt, 10, &(p.width));
|
||||
}
|
||||
|
||||
/* We accept 'x.y' format but don't support it completely:
|
||||
* we ignore the 'y' digit => this ignores 0-fill
|
||||
* size and makes it == width (ie. 'x') */
|
||||
if (ch == '.') {
|
||||
p.lz = 1; /* zero-padding */
|
||||
/* ignore actual 0-fill size: */
|
||||
do {
|
||||
ch = *(fmt++);
|
||||
} while ((ch >= '0') && (ch <= '9'));
|
||||
}
|
||||
|
||||
#ifdef PRINTF_SIZE_T_SUPPORT
|
||||
# ifdef PRINTF_LONG_SUPPORT
|
||||
if (ch == 'z') {
|
||||
ch = *(fmt++);
|
||||
if (sizeof(size_t) == sizeof(unsigned long int))
|
||||
lng = 1;
|
||||
# ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
else if (sizeof(size_t) == sizeof(unsigned long long int))
|
||||
lng = 2;
|
||||
# endif
|
||||
} else
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
if (ch == 'l') {
|
||||
ch = *(fmt++);
|
||||
lng = 1;
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (ch == 'l') {
|
||||
ch = *(fmt++);
|
||||
lng = 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
switch (ch) {
|
||||
case 0:
|
||||
goto abort;
|
||||
case 'u':
|
||||
p.base = 10;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
ulli2a(va_arg(va, unsigned long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
uli2a(va_arg(va, unsigned long int), &p);
|
||||
else
|
||||
#endif
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
p.base = 10;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
lli2a(va_arg(va, long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
li2a(va_arg(va, long int), &p);
|
||||
else
|
||||
#endif
|
||||
i2a(va_arg(va, int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
#ifdef SIZEOF_POINTER
|
||||
case 'p':
|
||||
p.alt = 1;
|
||||
# if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
|
||||
lng = 0;
|
||||
# elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
|
||||
lng = 1;
|
||||
# elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
|
||||
lng = 2;
|
||||
# endif
|
||||
#endif
|
||||
case 'x':
|
||||
case 'X':
|
||||
p.base = 16;
|
||||
p.uc = (ch == 'X')?1:0;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
ulli2a(va_arg(va, unsigned long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
uli2a(va_arg(va, unsigned long int), &p);
|
||||
else
|
||||
#endif
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'o':
|
||||
p.base = 8;
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'c':
|
||||
putf(putp, (char)(va_arg(va, int)));
|
||||
break;
|
||||
case 's':
|
||||
p.bf = va_arg(va, char *);
|
||||
putchw(putp, putf, &p);
|
||||
p.bf = bf;
|
||||
break;
|
||||
case '%':
|
||||
putf(putp, ch);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort:;
|
||||
}
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
static putcf stdout_putf;
|
||||
static void *stdout_putp;
|
||||
|
||||
void init_printf(void *putp, putcf putf)
|
||||
{
|
||||
stdout_putf = putf;
|
||||
stdout_putp = putp;
|
||||
}
|
||||
|
||||
void tfp_printf(char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
tfp_format(stdout_putp, stdout_putf, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
struct _vsnprintf_putcf_data
|
||||
{
|
||||
size_t dest_capacity;
|
||||
char *dest;
|
||||
size_t num_chars;
|
||||
};
|
||||
|
||||
static void _vsnprintf_putcf(void *p, char c)
|
||||
{
|
||||
struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
|
||||
if (data->num_chars < data->dest_capacity)
|
||||
data->dest[data->num_chars] = c;
|
||||
data->num_chars ++;
|
||||
}
|
||||
|
||||
int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
struct _vsnprintf_putcf_data data;
|
||||
|
||||
if (size < 1)
|
||||
return 0;
|
||||
|
||||
data.dest = str;
|
||||
data.dest_capacity = size-1;
|
||||
data.num_chars = 0;
|
||||
tfp_format(&data, _vsnprintf_putcf, format, ap);
|
||||
|
||||
if (data.num_chars < data.dest_capacity)
|
||||
data.dest[data.num_chars] = '\0';
|
||||
else
|
||||
data.dest[data.dest_capacity] = '\0';
|
||||
|
||||
return data.num_chars;
|
||||
}
|
||||
|
||||
int tfp_snprintf(char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int retval;
|
||||
|
||||
va_start(ap, format);
|
||||
retval = tfp_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct _vsprintf_putcf_data
|
||||
{
|
||||
char *dest;
|
||||
size_t num_chars;
|
||||
};
|
||||
|
||||
static void _vsprintf_putcf(void *p, char c)
|
||||
{
|
||||
struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
|
||||
data->dest[data->num_chars++] = c;
|
||||
}
|
||||
|
||||
int tfp_vsprintf(char *str, const char *format, va_list ap)
|
||||
{
|
||||
struct _vsprintf_putcf_data data;
|
||||
data.dest = str;
|
||||
data.num_chars = 0;
|
||||
tfp_format(&data, _vsprintf_putcf, format, ap);
|
||||
data.dest[data.num_chars] = '\0';
|
||||
return data.num_chars;
|
||||
}
|
||||
|
||||
int tfp_sprintf(char *str, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int retval;
|
||||
|
||||
va_start(ap, format);
|
||||
retval = tfp_vsprintf(str, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
186
src/tinyprintf.h
Normal file
186
src/tinyprintf.h
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
File: tinyprintf.h
|
||||
|
||||
Copyright (C) 2004 Kustaa Nyholm
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'.
|
||||
|
||||
They provide a simple and small (+400 loc) printf functionality to
|
||||
be used in embedded systems.
|
||||
|
||||
I've found them so useful in debugging that I do not bother with a
|
||||
debugger at all.
|
||||
|
||||
They are distributed in source form, so to use them, just compile them
|
||||
into your project.
|
||||
|
||||
Two printf variants are provided: printf and the 'sprintf' family of
|
||||
functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf').
|
||||
|
||||
The formats supported by this implementation are:
|
||||
'c' 'd' 'i' 'o' 'p' 'u' 's' 'x' 'X'.
|
||||
|
||||
Zero padding and field width are also supported.
|
||||
|
||||
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then
|
||||
the long specifier is also supported. Note that this will pull in some
|
||||
long math routines (pun intended!) and thus make your executable
|
||||
noticeably longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the
|
||||
long long specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t
|
||||
specifier.
|
||||
|
||||
The memory footprint of course depends on the target CPU, compiler and
|
||||
compiler options, but a rough guesstimate (based on a H8S target) is about
|
||||
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
|
||||
Not too bad. Your mileage may vary. By hacking the source code you can
|
||||
get rid of some hundred bytes, I'm sure, but personally I feel the balance of
|
||||
functionality and flexibility versus code size is close to optimal for
|
||||
many embedded systems.
|
||||
|
||||
To use the printf, you need to supply your own character output function,
|
||||
something like :
|
||||
|
||||
void putc ( void* p, char c)
|
||||
{
|
||||
while (!SERIAL_PORT_EMPTY) ;
|
||||
SERIAL_PORT_TX_REGISTER = c;
|
||||
}
|
||||
|
||||
Before you can call printf, you need to initialize it to use your
|
||||
character output function with something like:
|
||||
|
||||
init_printf(NULL,putc);
|
||||
|
||||
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
|
||||
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
|
||||
passed to your 'putc' routine. This allows you to pass some storage space (or
|
||||
anything really) to the character output function, if necessary.
|
||||
This is not often needed but it was implemented like that because it made
|
||||
implementing the sprintf function so neat (look at the source code).
|
||||
|
||||
The code is re-entrant, except for the 'init_printf' function, so it is safe
|
||||
to call it from interrupts too, although this may result in mixed output.
|
||||
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
|
||||
|
||||
The printf and sprintf functions are actually macros that translate to
|
||||
'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set
|
||||
(default). Setting it to 0 makes it possible to use them along with
|
||||
'stdio.h' printf's in a single source file. When
|
||||
'TINYPRINTF_OVERRIDE_LIBC' is set, please note that printf/sprintf are
|
||||
not function-like macros, so if you have variables or struct members
|
||||
with these names, things will explode in your face. Without variadic
|
||||
macros this is the best we can do to wrap these function. If it is a
|
||||
problem, just give up the macros and use the functions directly, or
|
||||
rename them.
|
||||
|
||||
It is also possible to avoid defining tfp_printf and/or tfp_sprintf by
|
||||
clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or
|
||||
'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to
|
||||
export only tfp_format, which is at the core of all the other
|
||||
functions.
|
||||
|
||||
For further details see source code.
|
||||
|
||||
regs Kusti, 23.10.2004
|
||||
*/
|
||||
|
||||
#ifndef __TFP_PRINTF__
|
||||
#define __TFP_PRINTF__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Global configuration */
|
||||
|
||||
/* Set this to 0 if you do not want to provide tfp_printf */
|
||||
#ifndef TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
# define TINYPRINTF_DEFINE_TFP_PRINTF 1
|
||||
#endif
|
||||
|
||||
/* Set this to 0 if you do not want to provide
|
||||
tfp_sprintf/snprintf/vsprintf/vsnprintf */
|
||||
#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
# define TINYPRINTF_DEFINE_TFP_SPRINTF 1
|
||||
#endif
|
||||
|
||||
/* Set this to 0 if you do not want tfp_printf and
|
||||
tfp_{vsn,sn,vs,s}printf to be also available as
|
||||
printf/{vsn,sn,vs,s}printf */
|
||||
#ifndef TINYPRINTF_OVERRIDE_LIBC
|
||||
# define TINYPRINTF_OVERRIDE_LIBC 1
|
||||
#endif
|
||||
|
||||
/* Optional external types dependencies */
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
# include <sys/types.h> /* size_t */
|
||||
#endif
|
||||
|
||||
/* Declarations */
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) \
|
||||
__attribute__((format (printf, fmt_idx, arg1_idx)))
|
||||
#else
|
||||
# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*putcf) (void *, char);
|
||||
|
||||
/*
|
||||
'tfp_format' really is the central function for all tinyprintf. For
|
||||
each output character after formatting, the 'putf' callback is
|
||||
called with 2 args:
|
||||
- an arbitrary void* 'putp' param defined by the user and
|
||||
passed unmodified from 'tfp_format',
|
||||
- the character.
|
||||
The 'tfp_printf' and 'tfp_sprintf' functions simply define their own
|
||||
callback and pass to it the right 'putp' it is expecting.
|
||||
*/
|
||||
void tfp_format(void *putp, putcf putf, const char *fmt, va_list va);
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
|
||||
int tfp_snprintf(char *str, size_t size, const char *fmt, ...) \
|
||||
_TFP_SPECIFY_PRINTF_FMT(3, 4);
|
||||
int tfp_vsprintf(char *str, const char *fmt, va_list ap);
|
||||
int tfp_sprintf(char *str, const char *fmt, ...) \
|
||||
_TFP_SPECIFY_PRINTF_FMT(2, 3);
|
||||
# if TINYPRINTF_OVERRIDE_LIBC
|
||||
# define vsnprintf tfp_vsnprintf
|
||||
# define snprintf tfp_snprintf
|
||||
# define vsprintf tfp_vsprintf
|
||||
# define sprintf tfp_sprintf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
void init_printf(void *putp, putcf putf);
|
||||
void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2);
|
||||
# if TINYPRINTF_OVERRIDE_LIBC
|
||||
# define printf tfp_printf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -22,14 +22,15 @@
|
|||
|
||||
|
||||
#include "usart_helpers.h"
|
||||
#define TINYPRINTF_OVERRIDE_LIBC 0
|
||||
#define TINYPRINTF_DEFINE_TFP_SPRINTF 0
|
||||
#include "tinyprintf.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <libopencm3/stm32/usart.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
|
||||
|
||||
#define USART_FIFO_OUT_SIZE (4096)
|
||||
uint8_t usart_fifo_out_data[USART_FIFO_OUT_SIZE];
|
||||
|
|
@ -103,35 +104,22 @@ static void usart_fifo_in_push(uint8_t aData)
|
|||
usart_fifo_in_len++;
|
||||
}
|
||||
|
||||
|
||||
static void usart_write(const char * data, uint32_t len)
|
||||
static void putf(void *arg, char c)
|
||||
{
|
||||
uint32_t i;
|
||||
for(i = 0; i < len; i++)
|
||||
{
|
||||
usart_fifo_push(data[i]);
|
||||
}
|
||||
//unused argument
|
||||
(void)arg;
|
||||
|
||||
usart_fifo_push(c);
|
||||
}
|
||||
|
||||
void usart_printf(const char *str, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, str);
|
||||
usart_vprintf(str, va);
|
||||
tfp_format(NULL, putf, str, va);
|
||||
va_end(va);
|
||||
|
||||
}
|
||||
|
||||
void usart_vprintf(const char *str, va_list va)
|
||||
{
|
||||
char databuffer[128];
|
||||
int i = vsnprintf(databuffer, 128, str, va);
|
||||
if (i > 0) {
|
||||
usart_write(databuffer, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void usart_init(uint32_t arg_usart, uint32_t baudrate)
|
||||
{
|
||||
usart_set_baudrate(arg_usart, baudrate);
|
||||
|
|
@ -145,6 +133,7 @@ void usart_init(uint32_t arg_usart, uint32_t baudrate)
|
|||
usart_enable(arg_usart);
|
||||
usart = arg_usart;
|
||||
}
|
||||
|
||||
void usart_interrupt(void)
|
||||
{
|
||||
if (usart_get_interrupt_source(usart, USART_SR_RXNE)) {
|
||||
|
|
@ -230,9 +219,7 @@ void usart_call_cmd(struct usart_commands * commands)
|
|||
LOG_PRINTF("#2");
|
||||
return;
|
||||
}
|
||||
//~ for (i = 0; i < command_len; i++) {
|
||||
//~ LOG_PRINTF("%c", command[i]);
|
||||
//~ }
|
||||
|
||||
i=0;
|
||||
while(commands[i].cmd != NULL) {
|
||||
if (!strcmp((char*)command, (char*)commands[i].cmd)) {
|
||||
|
|
@ -243,7 +230,7 @@ void usart_call_cmd(struct usart_commands * commands)
|
|||
commands[i].callback(&command[command_argindex]);
|
||||
}
|
||||
}
|
||||
usart_write("\n>>",4);
|
||||
LOG_PRINTF("\n>>");
|
||||
command_len = 0;
|
||||
command_argindex = 0;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ struct usart_commands{
|
|||
#ifdef USART_DEBUG
|
||||
void usart_init(uint32_t usart, uint32_t baudrate);
|
||||
void usart_printf(const char *str, ...);
|
||||
void usart_vprintf(const char *str, va_list va);
|
||||
void usart_fifo_send(void);
|
||||
|
||||
void usart_call_cmd(struct usart_commands * commands);
|
||||
|
|
|
|||
461
src/usbh_core.c
461
src/usbh_core.c
|
|
@ -28,12 +28,14 @@
|
|||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
static struct {
|
||||
bool enumeration_run;
|
||||
const usbh_low_level_driver_t * const *lld_drivers;
|
||||
const usbh_dev_driver_t * const *dev_drivers;
|
||||
int8_t address_temporary;
|
||||
} usbh_data = {0};
|
||||
} usbh_data = {};
|
||||
|
||||
static void set_enumeration(void)
|
||||
{
|
||||
|
|
@ -50,10 +52,20 @@ static bool enumeration(void)
|
|||
return usbh_data.enumeration_run;
|
||||
}
|
||||
|
||||
void device_remove(usbh_device_t *dev)
|
||||
{
|
||||
if (dev->drv && dev->drvdata) {
|
||||
dev->drv->remove(dev->drvdata);
|
||||
}
|
||||
dev->address = -1;
|
||||
dev->drv = NULL;
|
||||
dev->drvdata = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * device_info)
|
||||
static bool find_driver(usbh_device_t *dev, const usbh_dev_driver_info_t * device_info)
|
||||
{
|
||||
|
||||
#define CHECK_PARTIAL_COMPATIBILITY(what) \
|
||||
|
|
@ -63,7 +75,6 @@ static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * devic
|
|||
continue;\
|
||||
}
|
||||
|
||||
|
||||
int i = 0;
|
||||
|
||||
while (usbh_data.dev_drivers[i]) {
|
||||
|
|
@ -77,9 +88,16 @@ static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * devic
|
|||
CHECK_PARTIAL_COMPATIBILITY(idVendor);
|
||||
CHECK_PARTIAL_COMPATIBILITY(idProduct);
|
||||
|
||||
return usbh_data.dev_drivers[i];
|
||||
dev->drv = usbh_data.dev_drivers[i];
|
||||
dev->drvdata = dev->drv->init(dev);
|
||||
if (!dev->drvdata) {
|
||||
LOG_PRINTF("Unable to initialize device driver at index %d\n", i);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
#undef CHECK_PARTIAL_COMPATIBILITY
|
||||
}
|
||||
|
||||
|
|
@ -87,11 +105,10 @@ static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * devic
|
|||
static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
dev->drv = 0;
|
||||
uint8_t *buf = (uint8_t *)descriptors;
|
||||
|
||||
dev->drv = 0;
|
||||
dev->drvdata = 0;
|
||||
dev->drv = NULL;
|
||||
dev->drvdata = NULL;
|
||||
|
||||
uint8_t desc_len = buf[i];
|
||||
uint8_t desc_type = buf[i + 1];
|
||||
|
|
@ -122,14 +139,27 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de
|
|||
device_info.ifaceClass = iface->bInterfaceClass;
|
||||
device_info.ifaceSubClass = iface->bInterfaceSubClass;
|
||||
device_info.ifaceProtocol = iface->bInterfaceProtocol;
|
||||
const usbh_dev_driver_t *driver = find_driver(&device_info);
|
||||
if (driver) {
|
||||
dev->drv = driver;
|
||||
dev->drvdata = dev->drv->init(dev);
|
||||
if (!dev->drvdata) {
|
||||
LOG_PRINTF("CANT TOUCH THIS");
|
||||
if (find_driver(dev, &device_info)) {
|
||||
int k = 0;
|
||||
while (k < descriptors_len) {
|
||||
desc_len = buf[k];
|
||||
void *drvdata = dev->drvdata;
|
||||
LOG_PRINTF("[%d]", buf[k+1]);
|
||||
if (dev->drv->analyze_descriptor(drvdata, &buf[k])) {
|
||||
LOG_PRINTF("Device Initialized\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (desc_len == 0) {
|
||||
LOG_PRINTF("Problem occured while parsing complete configuration descriptor");
|
||||
return;
|
||||
}
|
||||
k += desc_len;
|
||||
}
|
||||
break;
|
||||
LOG_PRINTF("Device driver isn't compatible with this device\n");
|
||||
device_remove(dev);
|
||||
} else {
|
||||
LOG_PRINTF("No compatible driver has been found for interface #%d\n", iface->bInterfaceNumber);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -142,28 +172,11 @@ static void device_register(void *descriptors, uint16_t descriptors_len, usbh_de
|
|||
return;
|
||||
}
|
||||
i += desc_len;
|
||||
|
||||
}
|
||||
|
||||
if (dev->drv && dev->drvdata) {
|
||||
// analyze descriptors
|
||||
LOG_PRINTF("ANALYZE");
|
||||
i = 0;
|
||||
while (i < descriptors_len) {
|
||||
desc_len = buf[i];
|
||||
void *drvdata = dev->drvdata;
|
||||
LOG_PRINTF("[%d]",buf[i+1]);
|
||||
if (dev->drv->analyze_descriptor(drvdata, &buf[i])) {
|
||||
LOG_PRINTF("Device Initialized\n");
|
||||
return;
|
||||
}
|
||||
i += desc_len;
|
||||
}
|
||||
}
|
||||
LOG_PRINTF("Device NOT Initialized\n");
|
||||
}
|
||||
|
||||
void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const device_drivers[])
|
||||
void usbh_init(const usbh_low_level_driver_t * const low_level_drivers[], const usbh_dev_driver_t * const device_drivers[])
|
||||
{
|
||||
if (!low_level_drivers) {
|
||||
return;
|
||||
|
|
@ -172,10 +185,9 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const
|
|||
usbh_data.lld_drivers = (const usbh_low_level_driver_t **)low_level_drivers;
|
||||
usbh_data.dev_drivers = device_drivers;
|
||||
|
||||
// TODO: init structures
|
||||
uint32_t k = 0;
|
||||
while (usbh_data.lld_drivers[k]) {
|
||||
LOG_PRINTF("DRIVER %d\n", k);
|
||||
LOG_PRINTF("Initialization low-level driver with index=%d\n", k);
|
||||
|
||||
usbh_device_t * usbh_device =
|
||||
((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device;
|
||||
|
|
@ -186,7 +198,6 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const
|
|||
usbh_device[i].drv = 0;
|
||||
usbh_device[i].drvdata = 0;
|
||||
}
|
||||
LOG_PRINTF("DRIVER %d", k);
|
||||
usbh_data.lld_drivers[k]->init(usbh_data.lld_drivers[k]->driver_data);
|
||||
|
||||
k++;
|
||||
|
|
@ -194,15 +205,11 @@ void usbh_init(const void *low_level_drivers[], const usbh_dev_driver_t * const
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* NEW ENUMERATE
|
||||
*
|
||||
*/
|
||||
void device_xfer_control_write_setup(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_write_setup(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
packet.data = data;
|
||||
packet.data.out = data;
|
||||
packet.datalen = datalen;
|
||||
packet.address = dev->address;
|
||||
packet.endpoint_address = 0;
|
||||
|
|
@ -218,11 +225,11 @@ void device_xfer_control_write_setup(void *data, uint16_t datalen, usbh_packet_c
|
|||
LOG_PRINTF("WR-setup@device...%d \n", dev->address);
|
||||
}
|
||||
|
||||
void device_xfer_control_write_data(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_write_data(const void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
packet.data = data;
|
||||
packet.data.out = data;
|
||||
packet.datalen = datalen;
|
||||
packet.address = dev->address;
|
||||
packet.endpoint_address = 0;
|
||||
|
|
@ -238,11 +245,11 @@ void device_xfer_control_write_data(void *data, uint16_t datalen, usbh_packet_ca
|
|||
LOG_PRINTF("WR-data@device...%d \n", dev->address);
|
||||
}
|
||||
|
||||
void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
static void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
|
||||
{
|
||||
usbh_packet_t packet;
|
||||
|
||||
packet.data = data;
|
||||
packet.data.in = data;
|
||||
packet.datalen = datalen;
|
||||
packet.address = dev->address;
|
||||
packet.endpoint_address = 0;
|
||||
|
|
@ -258,6 +265,85 @@ void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback
|
|||
}
|
||||
|
||||
|
||||
static void control_state_machine(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
switch (dev->control.state) {
|
||||
case USBH_CONTROL_STATE_SETUP:
|
||||
if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
// Unable to deliver setup control packet - this is a fatal error
|
||||
usbh_packet_callback_data_t ret_data;
|
||||
ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
|
||||
ret_data.transferred_length = 0;
|
||||
dev->control.callback(dev, ret_data);
|
||||
break;
|
||||
}
|
||||
if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
|
||||
dev->control.state = USBH_CONTROL_STATE_DATA;
|
||||
device_xfer_control_read(dev->control.data.in, dev->control.data_length, control_state_machine, dev);
|
||||
} else {
|
||||
if (dev->control.data_length == 0) {
|
||||
dev->control.state = USBH_CONTROL_STATE_STATUS;
|
||||
device_xfer_control_read(NULL, 0, control_state_machine, dev);
|
||||
} else {
|
||||
dev->control.state = USBH_CONTROL_STATE_DATA;
|
||||
device_xfer_control_write_data(dev->control.data.out, dev->control.data_length, control_state_machine, dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_CONTROL_STATE_DATA:
|
||||
if (dev->control.setup_data.bmRequestType & USB_REQ_TYPE_IN) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
} else {
|
||||
if (cb_data.status != USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
// Unable to deliver data control packet - this is a fatal error
|
||||
usbh_packet_callback_data_t ret_data;
|
||||
ret_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
|
||||
ret_data.transferred_length = 0;
|
||||
dev->control.callback(dev, ret_data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->control.data_length == 0) {
|
||||
// we should be in status state when the length of data is zero
|
||||
LOG_PRINTF("Control logic error\n");
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
} else {
|
||||
dev->control.state = USBH_CONTROL_STATE_STATUS;
|
||||
device_xfer_control_read(NULL, 0, control_state_machine, dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_CONTROL_STATE_STATUS:
|
||||
dev->control.state = USBH_CONTROL_STATE_NONE;
|
||||
dev->control.callback(dev, cb_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void device_control(usbh_device_t *dev, usbh_packet_callback_t callback, const struct usb_setup_data *setup_data, void *data)
|
||||
{
|
||||
if (dev->control.state != USBH_CONTROL_STATE_NONE) {
|
||||
LOG_PRINTF("ERROR: Use of control state machine while not idle\n");
|
||||
return;
|
||||
}
|
||||
|
||||
dev->control.state = USBH_CONTROL_STATE_SETUP;
|
||||
dev->control.callback = callback;
|
||||
dev->control.data.out = data;
|
||||
dev->control.data_length = setup_data->wLength;
|
||||
dev->control.setup_data = *setup_data;
|
||||
device_xfer_control_write_setup(&dev->control.setup_data, sizeof(dev->control.setup_data), control_state_machine, dev);
|
||||
}
|
||||
|
||||
|
||||
bool usbh_enum_available(void)
|
||||
{
|
||||
|
|
@ -289,102 +375,62 @@ usbh_device_t *usbh_get_free_device(const usbh_device_t *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void device_enumeration_terminate(usbh_device_t *dev)
|
||||
static void device_enumeration_finish(usbh_device_t *dev)
|
||||
{
|
||||
reset_enumeration();
|
||||
dev->state = 0;
|
||||
dev->address = -1;
|
||||
dev->state = USBH_ENUM_STATE_FIRST;
|
||||
}
|
||||
|
||||
/* Do not call this function directly,
|
||||
* only via callback passing into low-level function
|
||||
* If you must, call it carefully ;)
|
||||
*/
|
||||
static void device_enumeration_terminate(usbh_device_t *dev)
|
||||
{
|
||||
dev->address = -1;
|
||||
device_enumeration_finish(dev);
|
||||
}
|
||||
|
||||
#define CONTINUE_WITH(en) \
|
||||
dev->state = en;\
|
||||
device_enumerate(dev, cb_data);
|
||||
|
||||
static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
const usbh_low_level_driver_t *lld = dev->lld;
|
||||
usbh_generic_data_t *lld_data = lld->driver_data;
|
||||
uint8_t *usbh_buffer = lld_data->usbh_buffer;
|
||||
uint8_t state_start = dev->state; // Detection of hang
|
||||
// LOG_PRINTF("\nSTATE: %d\n", state);
|
||||
switch (dev->state) {
|
||||
case 1:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
dev->state++;
|
||||
LOG_PRINTF("::%d::", dev->address);
|
||||
device_xfer_control_read(0, 0, device_enumerate, dev);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case USBH_ENUM_STATE_SET_ADDRESS:
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
if (dev->address == 0) {
|
||||
dev->address = usbh_data.address_temporary;
|
||||
LOG_PRINTF("ADDR: %d\n", dev->address);
|
||||
LOG_PRINTF("Assigned address: %d\n", dev->address);
|
||||
}
|
||||
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b10000000;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_DEVICE << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = USB_DT_DEVICE_SIZE;
|
||||
|
||||
dev->state++;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_DEVICE_DT_READ_SETUP);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
case USBH_ENUM_STATE_DEVICE_DT_READ_SETUP:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
dev->state++;
|
||||
device_xfer_control_read(&usbh_buffer[0], USB_DT_DEVICE_SIZE,
|
||||
device_enumerate, dev);
|
||||
break;
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
dev->state = 2;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_DEVICE << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = USB_DT_DEVICE_SIZE;
|
||||
|
||||
// WARNING: Recursion
|
||||
// .. but should work
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
device_enumerate(dev, cb_data);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
dev->state = USBH_ENUM_STATE_DEVICE_DT_READ_COMPLETE;
|
||||
device_control(dev, device_enumerate, &setup_data, &usbh_buffer[0]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case USBH_ENUM_STATE_DEVICE_DT_READ_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -392,17 +438,9 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
struct usb_device_descriptor *ddt =
|
||||
(struct usb_device_descriptor *)&usbh_buffer[0];
|
||||
dev->packet_size_max0 = ddt->bMaxPacketSize0;
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b10000000;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_CONFIGURATION << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = ddt->bMaxPacketSize0;//USB_DT_CONFIGURATION_SIZE;
|
||||
|
||||
dev->state++;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
LOG_PRINTF("Found device with vid=0x%04x pid=0x%04x\n", ddt->idVendor, ddt->idProduct);
|
||||
LOG_PRINTF("class=0x%02x subclass=0x%02x protocol=0x%02x\n", ddt->bDeviceClass, ddt->bDeviceSubClass, ddt->bDeviceProtocol);
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_SETUP)
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -411,17 +449,14 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
struct usb_device_descriptor *ddt =
|
||||
(struct usb_device_descriptor *)&usbh_buffer[0];
|
||||
dev->packet_size_max0 = ddt->bMaxPacketSize0;
|
||||
dev->state = 2;
|
||||
|
||||
// WARNING: Recursion
|
||||
// .. but should work
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
device_enumerate(dev, cb_data);
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_DEVICE_DT_READ_SETUP);
|
||||
} else {
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
|
|
@ -429,18 +464,32 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_SETUP:
|
||||
{
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_CONFIGURATION << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = dev->packet_size_max0;
|
||||
|
||||
dev->state = USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
dev->state++;
|
||||
dev->state = USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_COMPLETE;
|
||||
device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE],
|
||||
dev->packet_size_max0, device_enumerate, dev);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
|
|
@ -448,44 +497,25 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_HEADER_READ_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
struct usb_setup_data setup_data;
|
||||
LOG_PRINTF("WRITE: LEN: %d", cdt->wTotalLength);
|
||||
setup_data.bmRequestType = 0b10000000;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_CONFIGURATION << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = cdt->wTotalLength;
|
||||
|
||||
dev->state++;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
}
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_CONFIGURATION_DT_READ_SETUP);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
if (cb_data.transferred_length >= USB_DT_CONFIGURATION_SIZE) {
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
if (cb_data.transferred_length <= cdt->wTotalLength) {
|
||||
dev->state = 8;
|
||||
|
||||
// WARNING: Recursion
|
||||
// .. but should work
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
device_enumerate(dev, cb_data);
|
||||
if (cb_data.transferred_length == cdt->wTotalLength) {
|
||||
LOG_PRINTF("Configuration descriptor read complete. length: %d\n", cdt->wTotalLength);
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_SET_CONFIGURATION_SETUP);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
|
|
@ -493,22 +523,38 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_READ_SETUP:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
struct usb_setup_data setup_data;
|
||||
LOG_PRINTF("Getting complete configuration descriptor of length: %d bytes\n", cdt->wTotalLength);
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_CONFIGURATION << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = cdt->wTotalLength;
|
||||
|
||||
dev->state = USBH_ENUM_STATE_CONFIGURATION_DT_READ;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_READ:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
dev->state++;
|
||||
dev->state = USBH_ENUM_STATE_CONFIGURATION_DT_READ_COMPLETE;
|
||||
device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE],
|
||||
cdt->wTotalLength, device_enumerate, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
|
|
@ -516,24 +562,20 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
}
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case USBH_ENUM_STATE_CONFIGURATION_DT_READ_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
LOG_PRINTF("TOTAL_LENGTH: %d\n", cdt->wTotalLength);
|
||||
device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev);
|
||||
dev->state++;
|
||||
LOG_PRINTF("Configuration descriptor read complete. length: %d\n", cdt->wTotalLength);
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_SET_CONFIGURATION_SETUP);
|
||||
|
||||
reset_enumeration();
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
|
|
@ -542,20 +584,58 @@ static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_
|
|||
}
|
||||
break;
|
||||
|
||||
case USBH_ENUM_STATE_SET_CONFIGURATION_SETUP:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
setup_data.wValue = cdt->bConfigurationValue;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
dev->state = USBH_ENUM_STATE_SET_CONFIGURATION_COMPLETE;
|
||||
device_control(dev, device_enumerate, &setup_data, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_ENUM_STATE_SET_CONFIGURATION_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
CONTINUE_WITH(USBH_ENUM_STATE_FIND_DRIVER);
|
||||
break;
|
||||
|
||||
default:
|
||||
device_enumeration_terminate(dev);
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_ENUM_STATE_FIND_DRIVER:
|
||||
{
|
||||
struct usb_config_descriptor *cdt =
|
||||
(struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
|
||||
device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev);
|
||||
|
||||
device_enumeration_finish(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_PRINTF("Error: Unknown state "__FILE__"/%d\n", __LINE__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (state_start == dev->state) {
|
||||
LOG_PRINTF("\n !HANG %d\n", state_start);
|
||||
}
|
||||
}
|
||||
|
||||
void device_enumeration_start(usbh_device_t *dev)
|
||||
{
|
||||
set_enumeration();
|
||||
dev->state = 1;
|
||||
|
||||
// save address
|
||||
uint8_t address = dev->address;
|
||||
|
|
@ -571,16 +651,16 @@ void device_enumeration_start(usbh_device_t *dev)
|
|||
|
||||
LOG_PRINTF("\n\n\n ENUMERATION OF DEVICE@%d STARTED \n\n", address);
|
||||
|
||||
dev->state = USBH_ENUM_STATE_SET_ADDRESS;
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00000000;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_SET_ADDRESS;
|
||||
setup_data.wValue = address;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data),
|
||||
device_enumerate, dev);
|
||||
device_control(dev, device_enumerate, &setup_data, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -591,7 +671,7 @@ void usbh_poll(uint32_t time_curr_us)
|
|||
{
|
||||
uint32_t k = 0;
|
||||
while (usbh_data.lld_drivers[k]) {
|
||||
usbh_device_t * usbh_device =
|
||||
usbh_device_t *usbh_device =
|
||||
((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device;
|
||||
usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data;
|
||||
|
||||
|
|
@ -605,24 +685,17 @@ void usbh_poll(uint32_t time_curr_us)
|
|||
usbh_device[0].lld = usbh_data.lld_drivers[k];
|
||||
usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data);
|
||||
usbh_device[0].address = 1;
|
||||
usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
|
||||
|
||||
device_enumeration_start(&usbh_device[0]);
|
||||
break;
|
||||
|
||||
case USBH_POLL_STATUS_DEVICE_DISCONNECTED:
|
||||
{
|
||||
// Device disconnected
|
||||
if (usbh_device[0].drv && usbh_device[0].drvdata) {
|
||||
usbh_device[0].drv->remove(usbh_device[0].drvdata);
|
||||
}
|
||||
usbh_device[0].drv = 0;
|
||||
usbh_device[0].drvdata = 0;
|
||||
|
||||
usbh_device[0].control.state = USBH_CONTROL_STATE_NONE;
|
||||
uint32_t i;
|
||||
for (i = 1; i < USBH_MAX_DEVICES; i++) {
|
||||
usbh_device[i].address = -1;
|
||||
usbh_device[i].drv = 0;
|
||||
usbh_device[i].drvdata = 0;
|
||||
for (i = 0; i < USBH_MAX_DEVICES; i++) {
|
||||
device_remove(&usbh_device[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -24,39 +24,16 @@
|
|||
#include "usbh_driver_ac_midi_private.h"
|
||||
#include "usart_helpers.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <libopencm3/usb/midi.h>
|
||||
#include <libopencm3/usb/audio.h>
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
|
||||
|
||||
static void *midi_init(void *usbh_dev);
|
||||
static bool midi_analyze_descriptor(void *drvdata, void *descriptor);
|
||||
static void midi_poll(void *drvdata, uint32_t tflp);
|
||||
static void midi_remove(void *drvdata);
|
||||
|
||||
static midi_device_t midi_device[USBH_AC_MIDI_MAX_DEVICES];
|
||||
static const midi_config_t *midi_config = 0;
|
||||
static const midi_config_t *midi_config = NULL;
|
||||
static bool initialized = false;
|
||||
|
||||
static const usbh_dev_driver_info_t usbh_midi_driver_info = {
|
||||
.deviceClass = -1,
|
||||
.deviceSubClass = -1,
|
||||
.deviceProtocol = -1,
|
||||
.idVendor = -1,
|
||||
.idProduct = -1,
|
||||
.ifaceClass = 0x01,
|
||||
.ifaceSubClass = 0x03,
|
||||
.ifaceProtocol = -1,
|
||||
};
|
||||
|
||||
const usbh_dev_driver_t usbh_midi_driver = {
|
||||
.init = midi_init,
|
||||
.analyze_descriptor = midi_analyze_descriptor,
|
||||
.poll = midi_poll,
|
||||
.remove = midi_remove,
|
||||
.info = &usbh_midi_driver_info
|
||||
};
|
||||
|
||||
void midi_driver_init(const midi_config_t *config)
|
||||
{
|
||||
uint32_t i;
|
||||
|
|
@ -70,14 +47,14 @@ void midi_driver_init(const midi_config_t *config)
|
|||
*
|
||||
*
|
||||
*/
|
||||
static void *midi_init(void *usbh_dev)
|
||||
static void *init(usbh_device_t *usbh_dev)
|
||||
{
|
||||
if (!midi_config || !initialized) {
|
||||
LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
uint32_t i;
|
||||
midi_device_t *drvdata = 0;
|
||||
midi_device_t *drvdata = NULL;
|
||||
|
||||
// find free data space for midi device
|
||||
for (i = 0; i < USBH_AC_MIDI_MAX_DEVICES; i++) {
|
||||
|
|
@ -89,7 +66,7 @@ static void *midi_init(void *usbh_dev)
|
|||
drvdata->endpoint_in_toggle = 0;
|
||||
drvdata->endpoint_out_toggle = 0;
|
||||
drvdata->usbh_device = usbh_dev;
|
||||
drvdata->write_callback_user = 0;
|
||||
drvdata->write_callback_user = NULL;
|
||||
drvdata->sending = false;
|
||||
break;
|
||||
}
|
||||
|
|
@ -101,7 +78,7 @@ static void *midi_init(void *usbh_dev)
|
|||
/**
|
||||
* Returns true if all needed data are parsed
|
||||
*/
|
||||
static bool midi_analyze_descriptor(void *drvdata, void *descriptor)
|
||||
static bool analyze_descriptor(void *drvdata, void *descriptor)
|
||||
{
|
||||
midi_device_t *midi = drvdata;
|
||||
uint8_t desc_type = ((uint8_t *)descriptor)[1];
|
||||
|
|
@ -186,12 +163,13 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t status)
|
|||
midi_in_message(midi, midi->endpoint_in_maxpacketsize);
|
||||
midi->state = 25;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
midi_in_message(midi, status.transferred_length);
|
||||
midi->state = 25;
|
||||
break;
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
|
||||
default:
|
||||
LOG_PRINTF("FATAL ERROR, MIDI DRIVER DEAD \n");
|
||||
//~ dev->drv->remove();
|
||||
midi->state = 0;
|
||||
|
|
@ -206,30 +184,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t status)
|
|||
LOG_PRINTF("\n CAN'T TOUCH THIS... ignoring data\n");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
LOG_PRINTF("|empty packet read|");
|
||||
if (status.status == USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
midi->state++;
|
||||
device_xfer_control_read(0, 0, event, dev);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3: // Configured
|
||||
{
|
||||
if (status.status == USBH_PACKET_CALLBACK_STATUS_OK) {
|
||||
midi->state = 100;
|
||||
|
||||
midi->endpoint_in_toggle = 0;
|
||||
LOG_PRINTF("\nMIDI CONFIGURED\n");
|
||||
|
||||
// Notify user
|
||||
if (midi_config->notify_connected) {
|
||||
midi_config->notify_connected(midi->device_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -242,7 +197,7 @@ static void read_midi_in(void *drvdata, const uint8_t nextstate)
|
|||
usbh_packet_t packet;
|
||||
|
||||
packet.address = midi->usbh_device->address;
|
||||
packet.data = &midi->buffer[0];
|
||||
packet.data.in = &midi->buffer[0];
|
||||
packet.datalen = midi->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_address = midi->endpoint_in_address;
|
||||
packet.endpoint_size_max = midi->endpoint_in_maxpacketsize;
|
||||
|
|
@ -260,12 +215,11 @@ static void read_midi_in(void *drvdata, const uint8_t nextstate)
|
|||
*
|
||||
* @param t_us global time us
|
||||
*/
|
||||
static void midi_poll(void *drvdata, uint32_t t_us)
|
||||
static void poll(void *drvdata, uint32_t t_us)
|
||||
{
|
||||
(void)drvdata;
|
||||
|
||||
midi_device_t *midi = drvdata;
|
||||
usbh_device_t *dev = midi->usbh_device;
|
||||
switch (midi->state) {
|
||||
|
||||
/// Upon configuration, some controllers send additional error data
|
||||
|
|
@ -276,11 +230,13 @@ static void midi_poll(void *drvdata, uint32_t t_us)
|
|||
midi->state = 101;
|
||||
}
|
||||
break;
|
||||
|
||||
case 101:
|
||||
{
|
||||
read_midi_in(drvdata, 102);
|
||||
}
|
||||
break;
|
||||
|
||||
case 102:
|
||||
{
|
||||
// if elapsed MIDI initial delay microseconds
|
||||
|
|
@ -289,6 +245,7 @@ static void midi_poll(void *drvdata, uint32_t t_us)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 25:
|
||||
{
|
||||
read_midi_in(drvdata, 26);
|
||||
|
|
@ -297,18 +254,15 @@ static void midi_poll(void *drvdata, uint32_t t_us)
|
|||
|
||||
case 1:
|
||||
{
|
||||
//~ LOG_PRINTF("CFGVAL: %d\n", dev->config_val);
|
||||
struct usb_setup_data setup_data;
|
||||
midi->state = 100;
|
||||
|
||||
setup_data.bmRequestType = 0b00000000;
|
||||
setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
setup_data.wValue = midi->buffer[0];
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
midi->endpoint_in_toggle = 0;
|
||||
LOG_PRINTF("\nMIDI CONFIGURED\n");
|
||||
|
||||
midi->state++;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
// Notify user
|
||||
if (midi_config->notify_connected) {
|
||||
midi_config->notify_connected(midi->device_id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -362,7 +316,7 @@ void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_
|
|||
midi->sending = true;
|
||||
midi->write_callback_user = callback;
|
||||
|
||||
midi->write_packet.data = (void*)data; // it is safe cast since we are writing and function usbh_write cannot modify data
|
||||
midi->write_packet.data.out = data;
|
||||
midi->write_packet.datalen = length;
|
||||
midi->write_packet.address = dev->address;
|
||||
midi->write_packet.endpoint_address = midi->endpoint_out_address;
|
||||
|
|
@ -377,7 +331,7 @@ void usbh_midi_write(uint8_t device_id, const void *data, uint32_t length, midi_
|
|||
usbh_write(dev, &midi->write_packet);
|
||||
}
|
||||
|
||||
static void midi_remove(void *drvdata)
|
||||
static void remove(void *drvdata)
|
||||
{
|
||||
midi_device_t *midi = drvdata;
|
||||
|
||||
|
|
@ -389,3 +343,22 @@ static void midi_remove(void *drvdata)
|
|||
midi->endpoint_in_address = 0;
|
||||
midi->endpoint_out_address = 0;
|
||||
}
|
||||
|
||||
static const usbh_dev_driver_info_t usbh_midi_driver_info = {
|
||||
.deviceClass = -1,
|
||||
.deviceSubClass = -1,
|
||||
.deviceProtocol = -1,
|
||||
.idVendor = -1,
|
||||
.idProduct = -1,
|
||||
.ifaceClass = 0x01,
|
||||
.ifaceSubClass = 0x03,
|
||||
.ifaceProtocol = -1,
|
||||
};
|
||||
|
||||
const usbh_dev_driver_t usbh_midi_driver = {
|
||||
.init = init,
|
||||
.analyze_descriptor = analyze_descriptor,
|
||||
.poll = poll,
|
||||
.remove = remove,
|
||||
.info = &usbh_midi_driver_info
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,11 +30,9 @@
|
|||
|
||||
enum STATES {
|
||||
STATE_INACTIVE,
|
||||
STATE_READING_COMPLETE,
|
||||
STATE_INITIAL,
|
||||
STATE_READING_REQUEST,
|
||||
STATE_SET_CONFIGURATION_REQUEST,
|
||||
STATE_SET_CONFIGURATION_EMPTY_READ,
|
||||
STATE_SET_CONFIGURATION_COMPLETE
|
||||
STATE_READING_COMPLETE,
|
||||
};
|
||||
|
||||
#define GP_XBOX_CORRECT_TRANSFERRED_LENGTH 20
|
||||
|
|
@ -74,7 +72,7 @@ void gp_xbox_driver_init(const gp_xbox_config_t *config)
|
|||
*
|
||||
*
|
||||
*/
|
||||
static void *init(void *usbh_dev)
|
||||
static void *init(usbh_device_t *usbh_dev)
|
||||
{
|
||||
if (!initialized) {
|
||||
LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__);
|
||||
|
|
@ -91,7 +89,7 @@ static void *init(void *usbh_dev)
|
|||
drvdata->device_id = i;
|
||||
drvdata->endpoint_in_address = 0;
|
||||
drvdata->endpoint_in_toggle = 0;
|
||||
drvdata->usbh_device = (usbh_device_t *)usbh_dev;
|
||||
drvdata->usbh_device = usbh_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -132,7 +130,7 @@ static bool analyze_descriptor(void *drvdata, void *descriptor)
|
|||
}
|
||||
|
||||
if (gp_xbox->endpoint_in_address) {
|
||||
gp_xbox->state_next = STATE_SET_CONFIGURATION_REQUEST;
|
||||
gp_xbox->state_next = STATE_INITIAL;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -259,47 +257,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
gp_xbox->state_next = STATE_READING_REQUEST;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
ERROR(cb_data.status);
|
||||
gp_xbox->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SET_CONFIGURATION_EMPTY_READ:
|
||||
{
|
||||
LOG_PRINTF("|empty packet read|");
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
gp_xbox->state_next = STATE_SET_CONFIGURATION_COMPLETE;
|
||||
device_xfer_control_read(0, 0, event, dev);
|
||||
break;
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
gp_xbox->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_SET_CONFIGURATION_COMPLETE: // Configured
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
gp_xbox->state_next = STATE_READING_REQUEST;
|
||||
gp_xbox->endpoint_in_toggle = 0;
|
||||
LOG_PRINTF("\ngp_xbox CONFIGURED\n");
|
||||
if (gp_xbox_config->notify_connected) {
|
||||
gp_xbox_config->notify_connected(gp_xbox->device_id);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
gp_xbox->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
|
|
@ -326,7 +284,7 @@ static void read_gp_xbox_in(gp_xbox_device_t *gp_xbox)
|
|||
usbh_packet_t packet;
|
||||
|
||||
packet.address = gp_xbox->usbh_device->address;
|
||||
packet.data = &gp_xbox->buffer[0];
|
||||
packet.data.in = &gp_xbox->buffer[0];
|
||||
packet.datalen = gp_xbox->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_address = gp_xbox->endpoint_in_address;
|
||||
packet.endpoint_size_max = gp_xbox->endpoint_in_maxpacketsize;
|
||||
|
|
@ -351,7 +309,6 @@ static void poll(void *drvdata, uint32_t time_curr_us)
|
|||
(void)time_curr_us;
|
||||
|
||||
gp_xbox_device_t *gp_xbox = (gp_xbox_device_t *)drvdata;
|
||||
usbh_device_t *dev = gp_xbox->usbh_device;
|
||||
|
||||
switch (gp_xbox->state_next) {
|
||||
case STATE_READING_REQUEST:
|
||||
|
|
@ -360,19 +317,14 @@ static void poll(void *drvdata, uint32_t time_curr_us)
|
|||
}
|
||||
break;
|
||||
|
||||
case STATE_SET_CONFIGURATION_REQUEST:
|
||||
case STATE_INITIAL:
|
||||
{
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00000000;
|
||||
setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
setup_data.wValue = gp_xbox->configuration_value;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
gp_xbox->state_next = STATE_SET_CONFIGURATION_EMPTY_READ;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
gp_xbox->state_next = STATE_READING_REQUEST;
|
||||
gp_xbox->endpoint_in_toggle = 0;
|
||||
LOG_PRINTF("\ngp_xbox CONFIGURED\n");
|
||||
if (gp_xbox_config->notify_connected) {
|
||||
gp_xbox_config->notify_connected(gp_xbox->device_id);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
412
src/usbh_driver_hid.c
Normal file
412
src/usbh_driver_hid.c
Normal file
|
|
@ -0,0 +1,412 @@
|
|||
/*
|
||||
* This file is part of the libusbhost library
|
||||
* hosted at http://github.com/libusbhost/libusbhost
|
||||
*
|
||||
* Copyright (C) 2016 Amir Hammad <amir.hammad@hotmail.com>
|
||||
*
|
||||
*
|
||||
* libusbhost is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "driver/usbh_device_driver.h"
|
||||
#include "usbh_driver_hid.h"
|
||||
#include "usart_helpers.h"
|
||||
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
#include <libopencm3/usb/hid.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#define USB_HID_SET_REPORT 0x09
|
||||
#define USB_HID_SET_IDLE 0x0A
|
||||
|
||||
enum STATES {
|
||||
STATE_INACTIVE,
|
||||
STATE_READING_REQUEST,
|
||||
STATE_READING_COMPLETE_AND_CHECK_REPORT,
|
||||
STATE_SET_REPORT_EMPTY_READ,
|
||||
STATE_GET_REPORT_DESCRIPTOR_READ_SETUP,// configuration is complete at this point. We write request
|
||||
STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE,// after the read finishes, we parse that descriptor
|
||||
STATE_SET_IDLE,
|
||||
STATE_SET_IDLE_COMPLETE,
|
||||
};
|
||||
|
||||
enum REPORT_STATE {
|
||||
REPORT_STATE_NULL,
|
||||
REPORT_STATE_READY,
|
||||
REPORT_STATE_PENDING,
|
||||
};
|
||||
|
||||
struct _hid_device {
|
||||
usbh_device_t *usbh_device;
|
||||
uint8_t buffer[USBH_HID_BUFFER];
|
||||
uint16_t endpoint_in_maxpacketsize;
|
||||
uint8_t endpoint_in_address;
|
||||
enum STATES state_next;
|
||||
uint8_t endpoint_in_toggle;
|
||||
uint8_t device_id;
|
||||
uint8_t configuration_value;
|
||||
uint16_t report0_length;
|
||||
enum REPORT_STATE report_state;
|
||||
uint8_t report_data[USBH_HID_REPORT_BUFFER];
|
||||
uint8_t report_data_length;
|
||||
enum HID_TYPE hid_type;
|
||||
uint8_t interface_number;
|
||||
};
|
||||
typedef struct _hid_device hid_device_t;
|
||||
|
||||
struct hid_report_decriptor {
|
||||
struct usb_hid_descriptor header;
|
||||
struct _report_descriptor_info {
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t wDescriptorLength;
|
||||
} __attribute__((packed)) report_descriptors_info[];
|
||||
} __attribute__((packed));
|
||||
|
||||
static hid_device_t hid_device[USBH_HID_MAX_DEVICES];
|
||||
static hid_config_t hid_config;
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
void hid_driver_init(const hid_config_t *config)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
initialized = true;
|
||||
|
||||
hid_config = *config;
|
||||
for (i = 0; i < USBH_HID_MAX_DEVICES; i++) {
|
||||
hid_device[i].state_next = STATE_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
static void *init(usbh_device_t *usbh_dev)
|
||||
{
|
||||
if (!initialized) {
|
||||
LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
hid_device_t *drvdata = NULL;
|
||||
|
||||
// find free data space for HID device
|
||||
for (i = 0; i < USBH_HID_MAX_DEVICES; i++) {
|
||||
if (hid_device[i].state_next == STATE_INACTIVE) {
|
||||
drvdata = &hid_device[i];
|
||||
drvdata->device_id = i;
|
||||
drvdata->endpoint_in_address = 0;
|
||||
drvdata->endpoint_in_toggle = 0;
|
||||
drvdata->report0_length = 0;
|
||||
drvdata->usbh_device = usbh_dev;
|
||||
drvdata->report_state = REPORT_STATE_NULL;
|
||||
drvdata->hid_type = HID_TYPE_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return drvdata;
|
||||
}
|
||||
|
||||
static void parse_report_descriptor(hid_device_t *hid, const uint8_t *buffer, uint32_t length)
|
||||
{
|
||||
// TODO
|
||||
// Do some parsing!
|
||||
// add some checks
|
||||
hid->report_state = REPORT_STATE_READY;
|
||||
|
||||
// TODO: parse this from buffer!
|
||||
hid->report_data_length = 1;
|
||||
(void)buffer;
|
||||
(void)length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needed data are parsed
|
||||
*/
|
||||
static bool analyze_descriptor(void *drvdata, void *descriptor)
|
||||
{
|
||||
hid_device_t *hid = (hid_device_t *)drvdata;
|
||||
uint8_t desc_type = ((uint8_t *)descriptor)[1];
|
||||
switch (desc_type) {
|
||||
case USB_DT_CONFIGURATION:
|
||||
{
|
||||
const struct usb_config_descriptor * cfg = (const struct usb_config_descriptor*)descriptor;
|
||||
hid->configuration_value = cfg->bConfigurationValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_DEVICE:
|
||||
{
|
||||
const struct usb_device_descriptor *devDesc = (const struct usb_device_descriptor *)descriptor;
|
||||
(void)devDesc;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_INTERFACE:
|
||||
{
|
||||
const struct usb_interface_descriptor *ifDesc = (const struct usb_interface_descriptor *)descriptor;
|
||||
if (ifDesc->bInterfaceProtocol == 0x01) {
|
||||
hid->hid_type = HID_TYPE_KEYBOARD;
|
||||
hid->interface_number = ifDesc->bInterfaceNumber;
|
||||
} else if (ifDesc->bInterfaceProtocol == 0x02) {
|
||||
hid->hid_type = HID_TYPE_MOUSE;
|
||||
hid->interface_number = ifDesc->bInterfaceNumber;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_ENDPOINT:
|
||||
{
|
||||
const struct usb_endpoint_descriptor *ep = (const struct usb_endpoint_descriptor *)descriptor;
|
||||
if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) {
|
||||
uint8_t epaddr = ep->bEndpointAddress;
|
||||
if (epaddr & (1<<7)) {
|
||||
hid->endpoint_in_address = epaddr&0x7f;
|
||||
if (ep->wMaxPacketSize < USBH_HID_BUFFER) {
|
||||
hid->endpoint_in_maxpacketsize = ep->wMaxPacketSize;
|
||||
} else {
|
||||
hid->endpoint_in_maxpacketsize = USBH_HID_BUFFER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_HID:
|
||||
{
|
||||
const struct hid_report_decriptor *desc = (const struct hid_report_decriptor *)descriptor;
|
||||
if (desc->header.bNumDescriptors > 0 && desc->report_descriptors_info[0].bDescriptorType == USB_DT_REPORT) {
|
||||
hid->report0_length = desc->report_descriptors_info[0].wDescriptorLength;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (hid->endpoint_in_address && hid->report0_length) {
|
||||
hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_SETUP;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void report_event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
(void)cb_data;// UNUSED
|
||||
|
||||
hid_device_t *hid = (hid_device_t *)dev->drvdata;
|
||||
hid->report_state = REPORT_STATE_READY;
|
||||
}
|
||||
|
||||
static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
hid_device_t *hid = (hid_device_t *)dev->drvdata;
|
||||
|
||||
switch (hid->state_next) {
|
||||
case STATE_READING_COMPLETE_AND_CHECK_REPORT:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
if (hid_config.hid_in_message_handler) {
|
||||
hid_config.hid_in_message_handler(hid->device_id, hid->buffer, cb_data.transferred_length);
|
||||
}
|
||||
hid->state_next = STATE_READING_REQUEST;
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
hid->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE: // read complete, SET_IDLE to 0
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
LOG_PRINTF("READ REPORT COMPLETE \n");
|
||||
hid->state_next = STATE_READING_REQUEST;
|
||||
hid->endpoint_in_toggle = 0;
|
||||
|
||||
parse_report_descriptor(hid, hid->buffer, cb_data.transferred_length);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
hid->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void read_hid_in_endpoint(void *drvdata)
|
||||
{
|
||||
hid_device_t *hid = (hid_device_t *)drvdata;
|
||||
usbh_packet_t packet;
|
||||
|
||||
packet.address = hid->usbh_device->address;
|
||||
packet.data.in = &hid->buffer[0];
|
||||
packet.datalen = hid->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_address = hid->endpoint_in_address;
|
||||
packet.endpoint_size_max = hid->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT;
|
||||
packet.speed = hid->usbh_device->speed;
|
||||
packet.callback = event;
|
||||
packet.callback_arg = hid->usbh_device;
|
||||
packet.toggle = &hid->endpoint_in_toggle;
|
||||
|
||||
hid->state_next = STATE_READING_COMPLETE_AND_CHECK_REPORT;
|
||||
usbh_read(hid->usbh_device, &packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param time_curr_us - monotically rising time
|
||||
* unit is microseconds
|
||||
* @see usbh_poll()
|
||||
*/
|
||||
static void poll(void *drvdata, uint32_t time_curr_us)
|
||||
{
|
||||
(void)time_curr_us;
|
||||
|
||||
hid_device_t *hid = (hid_device_t *)drvdata;
|
||||
usbh_device_t *dev = hid->usbh_device;
|
||||
switch (hid->state_next) {
|
||||
case STATE_READING_REQUEST:
|
||||
{
|
||||
read_hid_in_endpoint(drvdata);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_GET_REPORT_DESCRIPTOR_READ_SETUP:
|
||||
{
|
||||
hid->endpoint_in_toggle = 0;
|
||||
// We support only the first report descriptor with index 0
|
||||
|
||||
// limit the size of the report descriptor!
|
||||
if (hid->report0_length > USBH_HID_BUFFER) {
|
||||
hid->report0_length = USBH_HID_BUFFER;
|
||||
}
|
||||
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_INTERFACE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = USB_DT_REPORT << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = hid->report0_length;
|
||||
|
||||
hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE;
|
||||
device_control(dev, event, &setup_data, hid->buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing - probably transfer is in progress
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove(void *drvdata)
|
||||
{
|
||||
hid_device_t *hid = (hid_device_t *)drvdata;
|
||||
hid->state_next = STATE_INACTIVE;
|
||||
hid->endpoint_in_address = 0;
|
||||
}
|
||||
|
||||
bool hid_set_report(uint8_t device_id, uint8_t val)
|
||||
{
|
||||
if (device_id >= USBH_HID_MAX_DEVICES) {
|
||||
LOG_PRINTF("invalid device id");
|
||||
return false;
|
||||
}
|
||||
|
||||
hid_device_t *hid = &hid_device[device_id];
|
||||
if (hid->report_state != REPORT_STATE_READY) {
|
||||
LOG_PRINTF("reporting is not ready\n");
|
||||
// store and update afterwards
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hid->report_data_length == 0) {
|
||||
LOG_PRINTF("reporting is not available (report len=0)\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct usb_setup_data setup_data;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
|
||||
setup_data.bRequest = USB_HID_SET_REPORT;
|
||||
setup_data.wValue = 0x02 << 8;
|
||||
setup_data.wIndex = hid->interface_number;
|
||||
setup_data.wLength = hid->report_data_length;
|
||||
|
||||
hid->report_data[0] = val;
|
||||
|
||||
hid->report_state = REPORT_STATE_PENDING;
|
||||
device_control(hid->usbh_device, report_event, &setup_data, &hid->report_data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hid_is_connected(uint8_t device_id)
|
||||
{
|
||||
if (device_id >= USBH_HID_MAX_DEVICES) {
|
||||
LOG_PRINTF("is connected: invalid device id");
|
||||
return false;
|
||||
}
|
||||
return hid_device[device_id].state_next == STATE_INACTIVE;
|
||||
}
|
||||
|
||||
|
||||
enum HID_TYPE hid_get_type(uint8_t device_id)
|
||||
{
|
||||
if (hid_is_connected(device_id)) {
|
||||
return HID_TYPE_NONE;
|
||||
}
|
||||
return hid_device[device_id].hid_type;
|
||||
}
|
||||
|
||||
static const usbh_dev_driver_info_t driver_info = {
|
||||
.deviceClass = -1,
|
||||
.deviceSubClass = -1,
|
||||
.deviceProtocol = -1,
|
||||
.idVendor = -1,
|
||||
.idProduct = -1,
|
||||
.ifaceClass = 0x03, // HID class
|
||||
.ifaceSubClass = -1,
|
||||
.ifaceProtocol = -1, // Do not care
|
||||
};
|
||||
|
||||
const usbh_dev_driver_t usbh_hid_driver = {
|
||||
.init = init,
|
||||
.analyze_descriptor = analyze_descriptor,
|
||||
.poll = poll,
|
||||
.remove = remove,
|
||||
.info = &driver_info
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
/*
|
||||
* This file is part of the libusbhost library
|
||||
* hosted at http://github.com/libusbhost/libusbhost
|
||||
*
|
||||
* Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
|
||||
*
|
||||
*
|
||||
* libusbhost is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library 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 Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "usbh_core.h"
|
||||
#include "driver/usbh_device_driver.h"
|
||||
#include "usbh_driver_hid_mouse.h"
|
||||
#include "usart_helpers.h"
|
||||
|
||||
#include <libopencm3/usb/usbstd.h>
|
||||
|
||||
enum STATES {
|
||||
STATE_INACTIVE,
|
||||
STATE_READING_COMPLETE,
|
||||
STATE_READING_REQUEST,
|
||||
STATE_SET_CONFIGURATION_REQUEST,
|
||||
STATE_SET_CONFIGURATION_EMPTY_READ,
|
||||
STATE_SET_CONFIGURATION_COMPLETE
|
||||
};
|
||||
|
||||
struct _hid_mouse_device {
|
||||
usbh_device_t *usbh_device;
|
||||
uint8_t buffer[USBH_HID_MOUSE_BUFFER];
|
||||
uint16_t endpoint_in_maxpacketsize;
|
||||
uint8_t endpoint_in_address;
|
||||
enum STATES state_next;
|
||||
uint8_t endpoint_in_toggle;
|
||||
uint8_t device_id;
|
||||
uint8_t configuration_value;
|
||||
};
|
||||
typedef struct _hid_mouse_device hid_mouse_device_t;
|
||||
|
||||
static hid_mouse_device_t mouse_device[USBH_HID_MOUSE_MAX_DEVICES];
|
||||
static const hid_mouse_config_t *mouse_config;
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
void hid_mouse_driver_init(const hid_mouse_config_t *config)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
initialized = true;
|
||||
|
||||
mouse_config = config;
|
||||
for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
|
||||
mouse_device[i].state_next = STATE_INACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void *init(void *usbh_dev)
|
||||
{
|
||||
if (!initialized) {
|
||||
LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t i;
|
||||
hid_mouse_device_t *drvdata = 0;
|
||||
|
||||
// find free data space for mouse device
|
||||
for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
|
||||
if (mouse_device[i].state_next == STATE_INACTIVE) {
|
||||
drvdata = &mouse_device[i];
|
||||
drvdata->device_id = i;
|
||||
drvdata->endpoint_in_address = 0;
|
||||
drvdata->endpoint_in_toggle = 0;
|
||||
drvdata->usbh_device = (usbh_device_t *)usbh_dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return drvdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if all needed data are parsed
|
||||
*/
|
||||
static bool analyze_descriptor(void *drvdata, void *descriptor)
|
||||
{
|
||||
hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
|
||||
uint8_t desc_type = ((uint8_t *)descriptor)[1];
|
||||
switch (desc_type) {
|
||||
case USB_DT_CONFIGURATION:
|
||||
{
|
||||
struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor;
|
||||
mouse->configuration_value = cfg->bConfigurationValue;
|
||||
}
|
||||
break;
|
||||
case USB_DT_DEVICE:
|
||||
break;
|
||||
case USB_DT_INTERFACE:
|
||||
break;
|
||||
case USB_DT_ENDPOINT:
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor*)descriptor;
|
||||
if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) {
|
||||
uint8_t epaddr = ep->bEndpointAddress;
|
||||
if (epaddr & (1<<7)) {
|
||||
mouse->endpoint_in_address = epaddr&0x7f;
|
||||
if (ep->wMaxPacketSize < USBH_HID_MOUSE_BUFFER) {
|
||||
mouse->endpoint_in_maxpacketsize = ep->wMaxPacketSize;
|
||||
} else {
|
||||
mouse->endpoint_in_maxpacketsize = USBH_HID_MOUSE_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (mouse->endpoint_in_address) {
|
||||
mouse->state_next = STATE_SET_CONFIGURATION_REQUEST;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
// TODO Class Specific descriptors
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
||||
{
|
||||
hid_mouse_device_t *mouse = (hid_mouse_device_t *)dev->drvdata;
|
||||
switch (mouse->state_next) {
|
||||
case STATE_READING_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
mouse->state_next = STATE_READING_REQUEST;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
ERROR(cb_data.status);
|
||||
mouse->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SET_CONFIGURATION_EMPTY_READ:
|
||||
{
|
||||
LOG_PRINTF("|empty packet read|");
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
mouse->state_next = STATE_SET_CONFIGURATION_COMPLETE;
|
||||
device_xfer_control_read(0, 0, event, dev);
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
ERROR(cb_data.status);
|
||||
mouse->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_SET_CONFIGURATION_COMPLETE: // Configured
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
mouse->state_next = STATE_READING_REQUEST;
|
||||
mouse->endpoint_in_toggle = 0;
|
||||
LOG_PRINTF("\nMOUSE CONFIGURED\n");
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
ERROR(cb_data.status);
|
||||
mouse->state_next = STATE_INACTIVE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void read_mouse_in(void *drvdata)
|
||||
{
|
||||
hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
|
||||
usbh_packet_t packet;
|
||||
|
||||
packet.address = mouse->usbh_device->address;
|
||||
packet.data = &mouse->buffer[0];
|
||||
packet.datalen = mouse->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_address = mouse->endpoint_in_address;
|
||||
packet.endpoint_size_max = mouse->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT;
|
||||
packet.speed = mouse->usbh_device->speed;
|
||||
packet.callback = event;
|
||||
packet.callback_arg = mouse->usbh_device;
|
||||
packet.toggle = &mouse->endpoint_in_toggle;
|
||||
|
||||
mouse->state_next = STATE_READING_COMPLETE;
|
||||
usbh_read(mouse->usbh_device, &packet);
|
||||
|
||||
// LOG_PRINTF("@MOUSE EP1 | \n");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param time_curr_us - monotically rising time
|
||||
* unit is microseconds
|
||||
* @see usbh_poll()
|
||||
*/
|
||||
static void poll(void *drvdata, uint32_t time_curr_us)
|
||||
{
|
||||
(void)time_curr_us;
|
||||
|
||||
hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
|
||||
usbh_device_t *dev = mouse->usbh_device;
|
||||
switch (mouse->state_next) {
|
||||
case STATE_READING_REQUEST:
|
||||
{
|
||||
read_mouse_in(drvdata);
|
||||
}
|
||||
break;
|
||||
|
||||
case STATE_SET_CONFIGURATION_REQUEST:
|
||||
{
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00000000;
|
||||
setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
setup_data.wValue = mouse->configuration_value;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
mouse->state_next = STATE_SET_CONFIGURATION_EMPTY_READ;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// do nothing - probably transfer is in progress
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove(void *drvdata)
|
||||
{
|
||||
hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
|
||||
mouse->state_next = STATE_INACTIVE;
|
||||
mouse->endpoint_in_address = 0;
|
||||
}
|
||||
|
||||
static const usbh_dev_driver_info_t driver_info = {
|
||||
.deviceClass = -1,
|
||||
.deviceSubClass = -1,
|
||||
.deviceProtocol = -1,
|
||||
.idVendor = -1,
|
||||
.idProduct = -1,
|
||||
.ifaceClass = 0x03,
|
||||
.ifaceSubClass = -1,
|
||||
.ifaceProtocol = 0x02
|
||||
};
|
||||
|
||||
const usbh_dev_driver_t usbh_hid_mouse_driver = {
|
||||
.init = init,
|
||||
.analyze_descriptor = analyze_descriptor,
|
||||
.poll = poll,
|
||||
.remove = remove,
|
||||
.info = &driver_info
|
||||
};
|
||||
|
|
@ -25,9 +25,9 @@
|
|||
#include "usart_helpers.h"
|
||||
#include "usbh_config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
static hub_device_t hub_device[USBH_MAX_HUBS];
|
||||
|
||||
static bool initialized = false;
|
||||
|
|
@ -41,11 +41,11 @@ void hub_driver_init(void)
|
|||
for (i = 0; i < USBH_MAX_HUBS; i++) {
|
||||
hub_device[i].device[0] = 0;
|
||||
hub_device[i].ports_num = 0;
|
||||
hub_device[i].current_port = -1;
|
||||
hub_device[i].current_port = CURRENT_PORT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void *init(void *usbh_dev)
|
||||
static void *init(usbh_device_t *usbh_dev)
|
||||
{
|
||||
if (!initialized) {
|
||||
LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__);
|
||||
|
|
@ -53,24 +53,23 @@ static void *init(void *usbh_dev)
|
|||
}
|
||||
|
||||
uint32_t i;
|
||||
hub_device_t *drvdata = 0;
|
||||
hub_device_t *drvdata = NULL;
|
||||
// find free data space for hub device
|
||||
for (i = 0; i < USBH_MAX_HUBS; i++) {
|
||||
if (hub_device[i].device[0] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOG_PRINTF("%{%d}",i);
|
||||
LOG_FLUSH();
|
||||
LOG_PRINTF("{%d}",i);
|
||||
if (i == USBH_MAX_HUBS) {
|
||||
LOG_PRINTF("ERRRRRRR");
|
||||
LOG_PRINTF("Unable to initialize hub driver");
|
||||
return 0;
|
||||
}
|
||||
|
||||
drvdata = &hub_device[i];
|
||||
drvdata->state = 0;
|
||||
drvdata->state = EVENT_STATE_NONE;
|
||||
drvdata->ports_num = 0;
|
||||
drvdata->device[0] = (usbh_device_t *)usbh_dev;
|
||||
drvdata->device[0] = usbh_dev;
|
||||
drvdata->busy = 0;
|
||||
drvdata->endpoint_in_address = 0;
|
||||
drvdata->endpoint_in_maxpacketsize = 0;
|
||||
|
|
@ -86,13 +85,6 @@ static bool analyze_descriptor(void *drvdata, void *descriptor)
|
|||
hub_device_t *hub = (hub_device_t *)drvdata;
|
||||
uint8_t desc_type = ((uint8_t *)descriptor)[1];
|
||||
switch (desc_type) {
|
||||
case USB_DT_CONFIGURATION:
|
||||
{
|
||||
struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor;
|
||||
hub->buffer[0] = cfg->bConfigurationValue;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_DT_ENDPOINT:
|
||||
{
|
||||
struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor *)descriptor;
|
||||
|
|
@ -110,7 +102,6 @@ static bool analyze_descriptor(void *drvdata, void *descriptor)
|
|||
case USB_DT_HUB:
|
||||
{
|
||||
struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)descriptor;
|
||||
//~ hub->ports_num = desc->head.bNbrPorts;
|
||||
if ( desc->head.bNbrPorts <= USBH_HUB_MAX_DEVICES) {
|
||||
hub->ports_num = desc->head.bNbrPorts;
|
||||
} else {
|
||||
|
|
@ -127,7 +118,7 @@ static bool analyze_descriptor(void *drvdata, void *descriptor)
|
|||
}
|
||||
|
||||
if (hub->endpoint_in_address) {
|
||||
hub->state = 1;
|
||||
hub->state = EVENT_STATE_INITIAL;
|
||||
LOG_PRINTF("end enum");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -141,7 +132,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
|
||||
LOG_PRINTF("\nHUB->STATE = %d\n", hub->state);
|
||||
switch (hub->state) {
|
||||
case 26:
|
||||
case EVENT_STATE_POLL:
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
|
|
@ -157,7 +148,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
// Driver error... port not found
|
||||
if (!psc) {
|
||||
// Continue reading status change endpoint
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -172,119 +163,45 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
if (hub->current_port >= 1) {
|
||||
if (hub->current_port != port) {
|
||||
LOG_PRINTF("X");
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct usb_setup_data setup_data;
|
||||
// If regular port event, else hub event
|
||||
if (port) {
|
||||
setup_data.bmRequestType = 0b10100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
} else {
|
||||
setup_data.bmRequestType = 0b10100000;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
|
||||
}
|
||||
|
||||
setup_data.bRequest = USB_REQ_GET_STATUS;
|
||||
setup_data.wValue = 0;
|
||||
setup_data.wIndex = port;
|
||||
setup_data.wLength = 4;
|
||||
hub->state = 31;
|
||||
hub->state = EVENT_STATE_GET_STATUS_COMPLETE;
|
||||
|
||||
hub->current_port = port;
|
||||
LOG_PRINTF("\n\nPORT FOUND: %d\n", port);
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
device_control(dev, event, &setup_data, &hub->hub_and_port_status[port]);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
hub->state = 0;
|
||||
hub->state = EVENT_STATE_NONE;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
|
||||
// In case of EAGAIN error, retry read on status endpoint
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
LOG_PRINTF("HUB: Retrying...\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case EMPTY_PACKET_READ_STATE:
|
||||
{
|
||||
LOG_PRINTF("|empty packet read|");
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
device_xfer_control_read(0, 0, event, dev);
|
||||
hub->state = hub->state_after_empty_read;
|
||||
hub->state_after_empty_read = 0;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
hub->state = hub->state_after_empty_read;
|
||||
event(dev, cb_data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // Get HUB Descriptor write
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
if (hub->ports_num) {
|
||||
hub->index = 0;
|
||||
hub->state = 6;
|
||||
LOG_PRINTF("No need to get HUB DESC\n");
|
||||
event(dev, cb_data);
|
||||
} else {
|
||||
hub->endpoint_in_toggle = 0;
|
||||
|
||||
struct usb_setup_data setup_data;
|
||||
hub->desc_len = hub->device[0]->packet_size_max0;
|
||||
|
||||
setup_data.bmRequestType = 0b10100000;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = 0x29<<8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = hub->desc_len;
|
||||
|
||||
hub->state++;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
LOG_PRINTF("DO Need to get HUB DESC\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // Get HUB Descriptor read
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
hub->state++;
|
||||
device_xfer_control_read(hub->buffer, hub->desc_len, event, dev); // "error dynamic size" - bad comment, investigate
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:// Hub descriptor found
|
||||
case EVENT_STATE_READ_HUB_DESCRIPTOR_COMPLETE:// Hub descriptor found
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -297,19 +214,19 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
struct usb_setup_data setup_data;
|
||||
hub->desc_len = hub_descriptor->head.bDescLength;
|
||||
|
||||
setup_data.bmRequestType = 0b10100000;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = 0x29<<8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = hub->desc_len;
|
||||
|
||||
hub->state = 4;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
hub->state = EVENT_STATE_READ_HUB_DESCRIPTOR_COMPLETE;
|
||||
device_control(dev, event, &setup_data, hub->buffer);
|
||||
break;
|
||||
} else if (hub_descriptor->head.bDescLength == hub->desc_len) {
|
||||
hub->ports_num = hub_descriptor->head.bNbrPorts;
|
||||
|
||||
hub->state++;
|
||||
hub->state = EVENT_STATE_ENABLE_PORTS;
|
||||
hub->index = 0;
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
event(dev, cb_data);
|
||||
|
|
@ -334,7 +251,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
LOG_PRINTF("INCREASE NUMBER OF ENABLED PORTS\n");
|
||||
hub->ports_num = USBH_HUB_MAX_DEVICES;
|
||||
}
|
||||
hub->state++;
|
||||
hub->state = EVENT_STATE_ENABLE_PORTS;
|
||||
hub->index = 0;
|
||||
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
|
|
@ -344,15 +261,14 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:// enable ports
|
||||
case EVENT_STATE_ENABLE_PORTS:// enable ports
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -361,182 +277,76 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
struct usb_setup_data setup_data;
|
||||
|
||||
LOG_PRINTF("[!%d!]",hub->index);
|
||||
setup_data.bmRequestType = 0b00100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = HUB_REQ_SET_FEATURE;
|
||||
setup_data.wValue = HUB_FEATURE_PORT_POWER;
|
||||
setup_data.wIndex = hub->index;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
hub->state_after_empty_read = hub->state;
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
device_control(dev, event, &setup_data, 0);
|
||||
} else {
|
||||
hub->state++;
|
||||
// TODO:
|
||||
// Delay Based on hub descriptor field bPwr2PwrGood
|
||||
// delay_ms_busy_loop(200);
|
||||
|
||||
LOG_PRINTF("\nHUB CONFIGURED & PORTS POWERED\n");
|
||||
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
event(dev, cb_data);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
// get device status
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b10100000;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_STATUS;
|
||||
setup_data.wValue = 0;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 4;
|
||||
|
||||
hub->state++;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
hub->state = EVENT_STATE_GET_PORT_STATUS;
|
||||
hub->index = 0;
|
||||
device_control(dev, event, &setup_data, hub->buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
device_xfer_control_read(hub->buffer, 4, event, dev);
|
||||
hub->index = 0;
|
||||
hub->state++;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
case EVENT_STATE_GET_PORT_STATUS:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
struct usb_setup_data setup_data;
|
||||
if (hub->index < hub->ports_num) {
|
||||
//TODO: process data contained in hub->buffer
|
||||
|
||||
setup_data.bmRequestType = 0b10100011;
|
||||
setup_data.bRequest = USB_REQ_GET_STATUS;
|
||||
setup_data.wValue = 0;
|
||||
setup_data.wIndex = ++hub->index;
|
||||
setup_data.wLength = 4;
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
hub->state++;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = USB_REQ_GET_STATUS;
|
||||
setup_data.wValue = 0;
|
||||
setup_data.wIndex = ++hub->index;
|
||||
setup_data.wLength = 4;
|
||||
|
||||
hub->state = EVENT_STATE_GET_PORT_STATUS;
|
||||
device_control(dev, event, &setup_data, hub->buffer);
|
||||
} else {
|
||||
hub->busy = 0;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
}
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
device_xfer_control_read(hub->buffer, 4, event, dev);
|
||||
hub->state++;
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
if (hub->index < hub->ports_num) {
|
||||
hub->state = 9;
|
||||
// process data contained in hub->buffer
|
||||
// TODO:
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
|
||||
event(dev, cb_data);
|
||||
} else {
|
||||
hub->busy = 0;
|
||||
hub->state = 25;
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 31: // Read port status
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
{
|
||||
int8_t port = hub->current_port;
|
||||
hub->state++;
|
||||
|
||||
// TODO: rework to endianess aware,
|
||||
// (maybe whole library is affected by this)
|
||||
// Detail:
|
||||
// Isn't universal. Here is endianess ok,
|
||||
// but on another architecture may be incorrect
|
||||
device_xfer_control_read(&hub->hub_and_port_status[port], 4, event, dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
ERROR(cb_data.status);
|
||||
// continue
|
||||
hub->state = 25;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
case EVENT_STATE_GET_STATUS_COMPLETE:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -556,7 +366,7 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
if (!hub->device[port]) {
|
||||
if (!usbh_enum_available() || hub->busy) {
|
||||
LOG_PRINTF("\n\t\t\tCannot enumerate %d %d\n", !usbh_enum_available(), hub->busy);
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -564,54 +374,49 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
// clear feature C_PORT_CONNECTION
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = HUB_REQ_CLEAR_FEATURE;
|
||||
setup_data.wValue = HUB_FEATURE_C_PORT_CONNECTION;
|
||||
setup_data.wIndex = port;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
hub->state_after_empty_read = 33;
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
hub->state = EVENT_STATE_PORT_RESET_REQ;
|
||||
device_control(dev, event, &setup_data, 0);
|
||||
|
||||
} else if(stc & (1<<HUB_FEATURE_PORT_RESET)) {
|
||||
// clear feature C_PORT_RESET
|
||||
// Reset processing is complete, enumerate device
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = HUB_REQ_CLEAR_FEATURE;
|
||||
setup_data.wValue = HUB_FEATURE_C_PORT_RESET;
|
||||
setup_data.wIndex = port;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
hub->state_after_empty_read = 35;
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
hub->state = EVENT_STATE_PORT_RESET_COMPLETE;
|
||||
|
||||
LOG_PRINTF("RESET");
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
device_control(dev, event, &setup_data, 0);
|
||||
} else {
|
||||
LOG_PRINTF("another STC %d\n", stc);
|
||||
}
|
||||
} else {
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
LOG_PRINTF("HUB status change\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
// continue
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 33:
|
||||
case EVENT_STATE_PORT_RESET_REQ:
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -622,48 +427,40 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
if ((stc) & (1<<HUB_FEATURE_PORT_CONNECTION)) {
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = HUB_REQ_SET_FEATURE;
|
||||
setup_data.wValue = HUB_FEATURE_PORT_RESET;
|
||||
setup_data.wIndex = port;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
hub->state_after_empty_read = 11;
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
hub->state = EVENT_STATE_GET_PORT_STATUS;
|
||||
|
||||
LOG_PRINTF("CONN");
|
||||
|
||||
hub->busy = 1;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
device_control(dev, event, &setup_data, 0);
|
||||
}
|
||||
} else {
|
||||
LOG_PRINTF("\t\t\t\tDISCONNECT EVENT\n");
|
||||
if (hub->device[port]->drv && hub->device[port]->drvdata) {
|
||||
hub->device[port]->drv->remove(hub->device[port]->drvdata);
|
||||
}
|
||||
hub->device[port]->address = -1;
|
||||
device_remove(hub->device[port]);
|
||||
|
||||
hub->device[port]->drv = 0;
|
||||
hub->device[port]->drvdata = 0;
|
||||
hub->device[port] = 0;
|
||||
hub->current_port = CURRENT_PORT_NONE;
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
hub->busy = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
// continue
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 35: // RESET COMPLETE, start enumeration
|
||||
case EVENT_STATE_PORT_RESET_COMPLETE: // RESET COMPLETE, start enumeration
|
||||
{
|
||||
switch (cb_data.status) {
|
||||
case USBH_PACKET_CALLBACK_STATUS_OK:
|
||||
|
|
@ -682,46 +479,52 @@ static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
|
|||
}
|
||||
if ((sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) &&
|
||||
!(sts & (1<<(HUB_FEATURE_PORT_HIGHSPEED)))) {
|
||||
#define DISABLE_LOW_SPEED
|
||||
#ifdef DISABLE_LOW_SPEED
|
||||
LOG_PRINTF("Low speed device");
|
||||
|
||||
// Disable Low speed device immediately
|
||||
struct usb_setup_data setup_data;
|
||||
|
||||
setup_data.bmRequestType = 0b00100011;
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE | USB_REQ_TYPE_ENDPOINT;
|
||||
setup_data.bRequest = HUB_REQ_CLEAR_FEATURE;
|
||||
setup_data.wValue = HUB_FEATURE_PORT_ENABLE;
|
||||
setup_data.wIndex = port;
|
||||
setup_data.wLength = 0;
|
||||
|
||||
// After write process another devices, poll for events
|
||||
hub->state_after_empty_read = 11;//Expecting all ports are powered (constant/non-changeable after init)
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
//Expecting all ports are powered (constant/non-changeable after init)
|
||||
hub->state = EVENT_STATE_GET_PORT_STATUS;
|
||||
|
||||
hub->current_port = CURRENT_PORT_NONE;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
device_control(dev, event, &setup_data, 0);
|
||||
#else
|
||||
hub->device[port]->speed = USBH_SPEED_LOW;
|
||||
LOG_PRINTF("Low speed device");
|
||||
hub->timestamp_us = hub->time_curr_us;
|
||||
hub->state = EVENT_STATE_SLEEP_500_MS; // schedule wait for 500ms
|
||||
#endif
|
||||
} else if (!(sts & (1<<(HUB_FEATURE_PORT_LOWSPEED))) &&
|
||||
!(sts & (1<<(HUB_FEATURE_PORT_HIGHSPEED)))) {
|
||||
hub->device[port]->speed = USBH_SPEED_FULL;
|
||||
LOG_PRINTF("Full speed device");
|
||||
hub->timestamp_us = hub->time_curr_us;
|
||||
hub->state = 100; // schedule wait for 500ms
|
||||
hub->state = EVENT_STATE_SLEEP_500_MS; // schedule wait for 500ms
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
LOG_PRINTF("%s:%d Do not know what to do, when device is disabled after reset\n", __FILE__, __LINE__);
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case USBH_PACKET_CALLBACK_STATUS_EFATAL:
|
||||
case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
|
||||
case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
|
||||
default:
|
||||
ERROR(cb_data.status);
|
||||
// continue
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -738,7 +541,7 @@ static void read_ep1(void *drvdata)
|
|||
usbh_packet_t packet;
|
||||
|
||||
packet.address = hub->device[0]->address;
|
||||
packet.data = hub->buffer;
|
||||
packet.data.in = hub->buffer;
|
||||
packet.datalen = hub->endpoint_in_maxpacketsize;
|
||||
packet.endpoint_address = hub->endpoint_in_address;
|
||||
packet.endpoint_size_max = hub->endpoint_in_maxpacketsize;
|
||||
|
|
@ -748,7 +551,7 @@ static void read_ep1(void *drvdata)
|
|||
packet.callback_arg = hub->device[0];
|
||||
packet.toggle = &hub->endpoint_in_toggle;
|
||||
|
||||
hub->state = 26;
|
||||
hub->state = EVENT_STATE_POLL;
|
||||
usbh_read(hub->device[0], &packet);
|
||||
LOG_PRINTF("@hub %d/EP1 | \n", hub->device[0]->address);
|
||||
|
||||
|
|
@ -767,7 +570,7 @@ static void poll(void *drvdata, uint32_t time_curr_us)
|
|||
hub->time_curr_us = time_curr_us;
|
||||
|
||||
switch (hub->state) {
|
||||
case 25:
|
||||
case EVENT_STATE_POLL_REQ:
|
||||
{
|
||||
if (usbh_enum_available()) {
|
||||
read_ep1(hub);
|
||||
|
|
@ -777,28 +580,36 @@ static void poll(void *drvdata, uint32_t time_curr_us)
|
|||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case EVENT_STATE_INITIAL:
|
||||
{
|
||||
LOG_PRINTF("CFGVAL: %d\n", hub->buffer[0]);
|
||||
struct usb_setup_data setup_data;
|
||||
if (hub->ports_num) {
|
||||
hub->index = 0;
|
||||
hub->state = EVENT_STATE_ENABLE_PORTS;
|
||||
LOG_PRINTF("No need to get HUB DESC\n");
|
||||
event(dev, (usbh_packet_callback_data_t){0, 0});
|
||||
} else {
|
||||
hub->endpoint_in_toggle = 0;
|
||||
|
||||
setup_data.bmRequestType = 0b00000000;
|
||||
setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
|
||||
setup_data.wValue = hub->buffer[0];
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = 0;
|
||||
struct usb_setup_data setup_data;
|
||||
hub->desc_len = hub->device[0]->packet_size_max0;
|
||||
|
||||
hub->state = EMPTY_PACKET_READ_STATE;
|
||||
hub->state_after_empty_read = 3;
|
||||
device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
|
||||
setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_DEVICE;
|
||||
setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
|
||||
setup_data.wValue = 0x29 << 8;
|
||||
setup_data.wIndex = 0;
|
||||
setup_data.wLength = hub->desc_len;
|
||||
|
||||
hub->state = EVENT_STATE_READ_HUB_DESCRIPTOR_COMPLETE;
|
||||
device_control(dev, event, &setup_data, hub->buffer);
|
||||
LOG_PRINTF("DO Need to get HUB DESC\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 100:
|
||||
case EVENT_STATE_SLEEP_500_MS:
|
||||
if (hub->time_curr_us - hub->timestamp_us > 500000) {
|
||||
int8_t port = hub->current_port;
|
||||
LOG_PRINTF("PORT: %d", port);
|
||||
LOG_PRINTF("\nNEW device at address: %d\n", hub->device[port]->address);
|
||||
LOG_PRINTF("PORT: %d\n", port);
|
||||
LOG_PRINTF("NEW device at address: %d\n", hub->device[port]->address);
|
||||
hub->device[port]->lld = hub->device[0]->lld;
|
||||
|
||||
device_enumeration_start(hub->device[port]);
|
||||
|
|
@ -812,7 +623,7 @@ static void poll(void *drvdata, uint32_t time_curr_us)
|
|||
// Only one device on bus can have address==0
|
||||
hub->busy = 0;
|
||||
|
||||
hub->state = 25;
|
||||
hub->state = EVENT_STATE_POLL_REQ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
@ -835,23 +646,11 @@ static void remove(void *drvdata)
|
|||
hub_device_t *hub = (hub_device_t *)drvdata;
|
||||
uint8_t i;
|
||||
|
||||
// Call fast... to avoid polling
|
||||
hub->state = 0;
|
||||
hub->state = EVENT_STATE_NONE;
|
||||
hub->endpoint_in_address = 0;
|
||||
hub->busy = 0;
|
||||
for (i = 1; i < USBH_HUB_MAX_DEVICES + 1; i++) {
|
||||
if (hub->device[i]) {
|
||||
if (hub->device[i]->drv && hub->device[i]->drvdata) {
|
||||
if (hub->device[i]->drv->remove != remove) {
|
||||
LOG_PRINTF("\t\t\t\tHUB REMOVE %d\n",hub->device[i]->address);
|
||||
hub->device[i]->drv->remove(hub->device[i]->drvdata);
|
||||
}
|
||||
}
|
||||
hub->device[i] = 0;
|
||||
}
|
||||
hub->device[0]->drv = 0;
|
||||
hub->device[0]->drvdata = 0;
|
||||
hub->device[0] = 0;
|
||||
for (i = 0; i < USBH_HUB_MAX_DEVICES + 1; i++) {
|
||||
hub->device[i] = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,19 @@
|
|||
|
||||
#define CURRENT_PORT_NONE -1
|
||||
|
||||
#define EMPTY_PACKET_READ_STATE 255
|
||||
enum EVENT_STATE {
|
||||
EVENT_STATE_NONE,
|
||||
EVENT_STATE_INITIAL,
|
||||
EVENT_STATE_POLL_REQ,
|
||||
EVENT_STATE_POLL,
|
||||
EVENT_STATE_READ_HUB_DESCRIPTOR_COMPLETE,
|
||||
EVENT_STATE_ENABLE_PORTS,
|
||||
EVENT_STATE_GET_PORT_STATUS,
|
||||
EVENT_STATE_PORT_RESET_REQ,
|
||||
EVENT_STATE_PORT_RESET_COMPLETE,
|
||||
EVENT_STATE_SLEEP_500_MS,
|
||||
EVENT_STATE_GET_STATUS_COMPLETE,
|
||||
};
|
||||
|
||||
struct _hub_device {
|
||||
usbh_device_t *device[USBH_HUB_MAX_DEVICES + 1];
|
||||
|
|
@ -69,8 +81,7 @@ struct _hub_device {
|
|||
uint16_t endpoint_in_maxpacketsize;
|
||||
uint8_t endpoint_in_address;
|
||||
uint8_t endpoint_in_toggle;
|
||||
uint8_t state;
|
||||
uint8_t state_after_empty_read;
|
||||
enum EVENT_STATE state;
|
||||
|
||||
uint8_t desc_len;
|
||||
uint16_t ports_num;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ struct _channel {
|
|||
enum CHANNEL_STATE state;
|
||||
usbh_packet_t packet;
|
||||
uint32_t data_index; //used in receive function
|
||||
uint8_t error_count;
|
||||
};
|
||||
typedef struct _channel channel_t;
|
||||
|
||||
|
|
@ -143,34 +142,31 @@ static void init(void *drvdata)
|
|||
REBASE(OTG_GUSBCFG) |= OTG_GUSBCFG_PHYSEL;
|
||||
}
|
||||
|
||||
static uint32_t usbh_to_stm32_endpoint_type(enum USBH_ENDPOINT_TYPE usbh_eptyp)
|
||||
{
|
||||
switch (usbh_eptyp) {
|
||||
case USBH_ENDPOINT_TYPE_CONTROL: return OTG_HCCHAR_EPTYP_CONTROL;
|
||||
case USBH_ENDPOINT_TYPE_BULK: return OTG_HCCHAR_EPTYP_BULK;
|
||||
|
||||
// Use bulk transfer also for interrupt, since no difference is on protocol layer
|
||||
// Except different behaviour of the core
|
||||
case USBH_ENDPOINT_TYPE_INTERRUPT: return OTG_HCCHAR_EPTYP_BULK;
|
||||
case USBH_ENDPOINT_TYPE_ISOCHRONOUS: return OTG_HCCHAR_EPTYP_ISOCHRONOUS;
|
||||
default:
|
||||
LOG_PRINTF("\n\n\n\nWRONG EP TYPE\n\n\n\n\n");
|
||||
return OTG_HCCHAR_EPTYP_CONTROL;
|
||||
}
|
||||
}
|
||||
|
||||
static void stm32f4_usbh_port_channel_setup(
|
||||
void *drvdata, uint32_t channel, uint32_t address,
|
||||
uint32_t eptyp, uint32_t epnum, uint32_t epdir,
|
||||
uint32_t max_packet_size)
|
||||
void *drvdata, uint32_t channel, uint32_t epdir)
|
||||
{
|
||||
usbh_lld_stm32f4_driver_data_t *dev = drvdata;
|
||||
channel_t *channels = dev->channels;
|
||||
|
||||
// TODO: maybe to function
|
||||
switch (eptyp) {
|
||||
case USBH_ENDPOINT_TYPE_CONTROL:
|
||||
eptyp = OTG_HCCHAR_EPTYP_CONTROL;
|
||||
break;
|
||||
case USBH_ENDPOINT_TYPE_BULK:
|
||||
eptyp = OTG_HCCHAR_EPTYP_BULK;
|
||||
break;
|
||||
case USBH_ENDPOINT_TYPE_INTERRUPT:
|
||||
// Use bulk transfer also for interrupt, since no difference is on protocol layer
|
||||
// Except different behaviour of the core
|
||||
eptyp = OTG_HCCHAR_EPTYP_BULK;
|
||||
break;
|
||||
case USBH_ENDPOINT_TYPE_ISOCHRONOUS:
|
||||
eptyp = OTG_HCCHAR_EPTYP_ISOCHRONOUS;
|
||||
break;
|
||||
default:
|
||||
LOG_PRINTF("\n\n\n\nWRONG EP TYPE\n\n\n\n\n");
|
||||
return;
|
||||
}
|
||||
uint32_t max_packet_size = channels[channel].packet.endpoint_size_max;
|
||||
uint32_t address = channels[channel].packet.address;
|
||||
uint32_t epnum = channels[channel].packet.endpoint_address;
|
||||
uint32_t eptyp = usbh_to_stm32_endpoint_type(channels[channel].packet.endpoint_type);
|
||||
|
||||
uint32_t speed = 0;
|
||||
if (channels[channel].packet.speed == USBH_SPEED_LOW) {
|
||||
|
|
@ -182,7 +178,7 @@ static void stm32f4_usbh_port_channel_setup(
|
|||
OTG_HCCHAR_MCNT_1 |
|
||||
(OTG_HCCHAR_EPTYP_MASK & (eptyp)) |
|
||||
(speed) |
|
||||
(epdir) |
|
||||
(OTG_HCCHAR_EPDIR_MASK & epdir) |
|
||||
(OTG_HCCHAR_EPNUM_MASK & (epnum << 11)) |
|
||||
(OTG_HCCHAR_MPSIZ_MASK & max_packet_size);
|
||||
|
||||
|
|
@ -227,12 +223,7 @@ static void read(void *drvdata, usbh_packet_t *packet)
|
|||
|
||||
REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen;
|
||||
|
||||
stm32f4_usbh_port_channel_setup(dev, channel,
|
||||
packet->address,
|
||||
packet->endpoint_type,
|
||||
packet->endpoint_address,
|
||||
OTG_HCCHAR_EPDIR_IN,
|
||||
packet->endpoint_size_max);
|
||||
stm32f4_usbh_port_channel_setup(dev, channel, OTG_HCCHAR_EPDIR_IN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -284,18 +275,13 @@ static void write(void *drvdata, const usbh_packet_t *packet)
|
|||
}
|
||||
REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen;
|
||||
|
||||
stm32f4_usbh_port_channel_setup(dev, channel,
|
||||
packet->address,
|
||||
packet->endpoint_type,
|
||||
packet->endpoint_address,
|
||||
OTG_HCCHAR_EPDIR_OUT,
|
||||
packet->endpoint_size_max);
|
||||
stm32f4_usbh_port_channel_setup(dev, channel, OTG_HCCHAR_EPDIR_OUT);
|
||||
|
||||
if (packet->endpoint_type == USBH_ENDPOINT_TYPE_CONTROL ||
|
||||
packet->endpoint_type == USBH_ENDPOINT_TYPE_BULK) {
|
||||
|
||||
volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE;
|
||||
const uint32_t * buf32 = packet->data;
|
||||
const uint32_t * buf32 = packet->data.out;
|
||||
int i;
|
||||
LOG_PRINTF("\nSending[%d]: ", packet->datalen);
|
||||
for(i = packet->datalen; i >= 4; i-=4) {
|
||||
|
|
@ -317,7 +303,7 @@ static void write(void *drvdata, const usbh_packet_t *packet)
|
|||
} else {
|
||||
volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) +
|
||||
RX_FIFO_SIZE + TX_NP_FIFO_SIZE;
|
||||
const uint32_t * buf32 = packet->data;
|
||||
const uint32_t * buf32 = packet->data.out;
|
||||
int i;
|
||||
for(i = packet->datalen; i > 0; i-=4) {
|
||||
*fifo++ = *buf32++;
|
||||
|
|
@ -334,7 +320,7 @@ static void rxflvl_handle(void *drvdata)
|
|||
uint8_t channel = rxstsp&0xf;
|
||||
uint32_t len = (rxstsp>>4) & 0x1ff;
|
||||
if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN) {
|
||||
uint8_t *data = channels[channel].packet.data;
|
||||
uint8_t *data = channels[channel].packet.data.in;
|
||||
uint32_t *buf32 = (uint32_t *)&data[channels[channel].data_index];
|
||||
|
||||
int32_t i;
|
||||
|
|
@ -366,7 +352,7 @@ static void rxflvl_handle(void *drvdata)
|
|||
uint32_t i;
|
||||
LOG_PRINTF("\nDATA: ");
|
||||
for (i = 0; i < channels[channel].data_index; i++) {
|
||||
uint8_t *data = channels[channel].packet.data;
|
||||
uint8_t *data = channels[channel].packet.data.in;
|
||||
LOG_PRINTF("%02X ", data[i]);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -504,9 +490,17 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev)
|
|||
|
||||
if (hcint & OTG_HCINT_NAK) {
|
||||
REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_NAK;
|
||||
LOG_PRINTF("NAK");
|
||||
LOG_PRINTF("NAK\n");
|
||||
|
||||
REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHENA;
|
||||
free_channel(dev, channel);
|
||||
|
||||
usbh_packet_callback_data_t cb_data;
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_EAGAIN;
|
||||
cb_data.transferred_length = channels[channel].data_index;
|
||||
|
||||
channels[channel].packet.callback(
|
||||
channels[channel].packet.callback_arg,
|
||||
cb_data);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -540,6 +534,8 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev)
|
|||
REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_FRMOR;
|
||||
LOG_PRINTF("FRMOR");
|
||||
|
||||
free_channel(dev, channel);
|
||||
|
||||
usbh_packet_callback_data_t cb_data;
|
||||
cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
|
||||
cb_data.transferred_length = 0;
|
||||
|
|
@ -547,7 +543,6 @@ static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev)
|
|||
channels[channel].packet.callback(
|
||||
channels[channel].packet.callback_arg,
|
||||
cb_data);
|
||||
free_channel(dev, channel);
|
||||
}
|
||||
|
||||
if (hcint & OTG_HCINT_TXERR) {
|
||||
|
|
@ -922,7 +917,6 @@ static int8_t get_free_channel(void *drvdata)
|
|||
OTG_HCINTMSK_CHHM | OTG_HCINTMSK_STALLM |
|
||||
OTG_HCINTMSK_FRMORM;
|
||||
REBASE(OTG_HAINTMSK) |= (1 << i);
|
||||
dev->channels[i].error_count = 0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
@ -1013,7 +1007,7 @@ static usbh_lld_stm32f4_driver_data_t driver_data_fs = {
|
|||
.channels = channels_fs,
|
||||
.num_channels = NUM_CHANNELS_FS
|
||||
};
|
||||
static const usbh_low_level_driver_t driver_fs = {
|
||||
const usbh_low_level_driver_t usbh_lld_stm32f4_driver_fs = {
|
||||
.init = init,
|
||||
.poll = poll,
|
||||
.read = read,
|
||||
|
|
@ -1021,7 +1015,6 @@ static const usbh_low_level_driver_t driver_fs = {
|
|||
.root_speed = root_speed,
|
||||
.driver_data = &driver_data_fs
|
||||
};
|
||||
const void *usbh_lld_stm32f4_driver_fs = &driver_fs;
|
||||
#endif
|
||||
|
||||
// USB High Speed - OTG_HS
|
||||
|
|
@ -1033,7 +1026,8 @@ static usbh_lld_stm32f4_driver_data_t driver_data_hs = {
|
|||
.channels = channels_hs,
|
||||
.num_channels = NUM_CHANNELS_HS
|
||||
};
|
||||
static const usbh_low_level_driver_t driver_hs = {
|
||||
|
||||
const usbh_low_level_driver_t usbh_lld_stm32f4_driver_hs = {
|
||||
.init = init,
|
||||
.poll = poll,
|
||||
.read = read,
|
||||
|
|
@ -1041,5 +1035,5 @@ static const usbh_low_level_driver_t driver_hs = {
|
|||
.root_speed = root_speed,
|
||||
.driver_data = &driver_data_hs
|
||||
};
|
||||
const void *usbh_lld_stm32f4_driver_hs = &driver_hs;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue