diff options
Diffstat (limited to 'os/hal')
-rw-r--r-- | os/hal/hal.mk | 32 | ||||
-rw-r--r-- | os/hal/include/hal_community.h | 16 | ||||
-rw-r--r-- | os/hal/include/hal_crc.h (renamed from os/hal/include/crc.h) | 2 | ||||
-rw-r--r-- | os/hal/include/hal_ee24xx.h (renamed from os/hal/include/ee24xx.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_ee25xx.h (renamed from os/hal/include/ee25xx.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_eeprom.h (renamed from os/hal/include/eeprom.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_eicu.h (renamed from os/hal/include/eicu.h) | 2 | ||||
-rw-r--r-- | os/hal/include/hal_nand.h (renamed from os/hal/include/nand.h) | 2 | ||||
-rw-r--r-- | os/hal/include/hal_onewire.h (renamed from os/hal/include/onewire.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_rng.h (renamed from os/hal/include/rng.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_timcap.h (renamed from os/hal/include/timcap.h) | 0 | ||||
-rw-r--r-- | os/hal/include/hal_usbh.h (renamed from os/hal/include/usbh.h) | 878 | ||||
-rw-r--r-- | os/hal/include/usbh/debug.h | 2 | ||||
-rw-r--r-- | os/hal/include/usbh/dev/ftdi.h | 2 | ||||
-rw-r--r-- | os/hal/include/usbh/dev/hub.h | 2 | ||||
-rw-r--r-- | os/hal/include/usbh/dev/msd.h | 2 | ||||
-rw-r--r-- | os/hal/include/usbh/internal.h | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c (renamed from os/hal/ports/STM32/LLD/CRCv1/crc_lld.c) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h (renamed from os/hal/ports/STM32/LLD/CRCv1/crc_lld.h) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c (renamed from os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c) | 6260 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h (renamed from os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h) | 1328 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc.c) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc.h) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h (renamed from os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c (renamed from os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h (renamed from os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c (renamed from os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c) | 7584 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h (renamed from os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h) | 1472 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c (renamed from os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h (renamed from os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c (renamed from os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c) | 2 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h (renamed from os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h) | 0 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h (renamed from os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h) | 1858 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c (renamed from os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c) | 3208 | ||||
-rw-r--r-- | os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h (renamed from os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h) | 306 | ||||
-rw-r--r-- | os/hal/ports/STM32/STM32F0xx/platform.mk | 4 | ||||
-rw-r--r-- | os/hal/ports/STM32/STM32F3xx/platform.mk | 6 | ||||
-rw-r--r-- | os/hal/ports/STM32/STM32F4xx/platform.mk | 20 | ||||
-rw-r--r-- | os/hal/src/hal_crc.c (renamed from os/hal/src/crc.c) | 0 | ||||
-rw-r--r-- | os/hal/src/hal_ee24xx.c (renamed from os/hal/src/ee24xx.c) | 2 | ||||
-rw-r--r-- | os/hal/src/hal_ee25xx.c (renamed from os/hal/src/ee25xx.c) | 2 | ||||
-rw-r--r-- | os/hal/src/hal_eeprom.c (renamed from os/hal/src/eeprom.c) | 2 | ||||
-rw-r--r-- | os/hal/src/hal_eicu.c (renamed from os/hal/src/eicu.c) | 0 | ||||
-rw-r--r-- | os/hal/src/hal_nand.c (renamed from os/hal/src/nand.c) | 0 | ||||
-rw-r--r-- | os/hal/src/hal_onewire.c (renamed from os/hal/src/onewire.c) | 0 | ||||
-rw-r--r-- | os/hal/src/hal_rng.c (renamed from os/hal/src/rng.c) | 0 | ||||
-rw-r--r-- | os/hal/src/hal_timcap.c (renamed from os/hal/src/timcap.c) | 2 | ||||
-rw-r--r-- | os/hal/src/hal_usbh.c (renamed from os/hal/src/usbh.c) | 2790 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_debug.c (renamed from os/hal/src/usbh/usbh_debug.c) | 1072 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_desciter.c (renamed from os/hal/src/usbh/usbh_desciter.c) | 330 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_ftdi.c (renamed from os/hal/src/usbh/usbh_ftdi.c) | 1434 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_hub.c (renamed from os/hal/src/usbh/usbh_hub.c) | 604 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_msd.c (renamed from os/hal/src/usbh/usbh_msd.c) | 1878 | ||||
-rw-r--r-- | os/hal/src/usbh/hal_usbh_uvc.c (renamed from os/hal/src/usbh/usbh_uvc.c) | 178 |
57 files changed, 15648 insertions, 15648 deletions
diff --git a/os/hal/hal.mk b/os/hal/hal.mk index 8dc09f7..ec524ac 100644 --- a/os/hal/hal.mk +++ b/os/hal/hal.mk @@ -1,21 +1,21 @@ include ${CHIBIOS}/os/hal/hal.mk
HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/nand.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/onewire.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/eicu.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/crc.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/rng.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_debug.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_desciter.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_hub.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_msd.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_ftdi.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/usbh/usbh_uvc.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/ee24xx.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/ee25xx.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/eeprom.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/timcap.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_nand.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_onewire.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_eicu.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_crc.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_rng.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_usbh.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_debug.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_desciter.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_hub.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_msd.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_ftdi.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/usbh/hal_usbh_uvc.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_ee24xx.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_ee25xx.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_eeprom.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_timcap.c \
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include
diff --git a/os/hal/include/hal_community.h b/os/hal/include/hal_community.h index 144e495..6420964 100644 --- a/os/hal/include/hal_community.h +++ b/os/hal/include/hal_community.h @@ -30,16 +30,16 @@ /* Shared headers.*/
/* Normal drivers.*/
-#include "nand.h"
-#include "eicu.h"
-#include "rng.h"
-#include "usbh.h"
-#include "timcap.h"
+#include "hal_nand.h"
+#include "hal_eicu.h"
+#include "hal_rng.h"
+#include "hal_usbh.h"
+#include "hal_timcap.h"
/* Complex drivers.*/
-#include "onewire.h"
-#include "crc.h"
-#include "eeprom.h"
+#include "hal_onewire.h"
+#include "hal_crc.h"
+#include "hal_eeprom.h"
/*===========================================================================*/
/* Driver constants. */
diff --git a/os/hal/include/crc.h b/os/hal/include/hal_crc.h index afa27e1..8c4c895 100644 --- a/os/hal/include/crc.h +++ b/os/hal/include/hal_crc.h @@ -72,7 +72,7 @@ typedef enum { CRC_COMPLETE /* Asynchronous operation complete. */ } crcstate_t; -#include "crc_lld.h" +#include "hal_crc_lld.h" #include "crcsw.h" /* Include software LL driver */ diff --git a/os/hal/include/ee24xx.h b/os/hal/include/hal_ee24xx.h index ab12fd1..ab12fd1 100644 --- a/os/hal/include/ee24xx.h +++ b/os/hal/include/hal_ee24xx.h diff --git a/os/hal/include/ee25xx.h b/os/hal/include/hal_ee25xx.h index fc2ad6f..fc2ad6f 100644 --- a/os/hal/include/ee25xx.h +++ b/os/hal/include/hal_ee25xx.h diff --git a/os/hal/include/eeprom.h b/os/hal/include/hal_eeprom.h index b0fd360..b0fd360 100644 --- a/os/hal/include/eeprom.h +++ b/os/hal/include/hal_eeprom.h diff --git a/os/hal/include/eicu.h b/os/hal/include/hal_eicu.h index d9e08de..d4b0ed2 100644 --- a/os/hal/include/eicu.h +++ b/os/hal/include/hal_eicu.h @@ -90,7 +90,7 @@ typedef struct EICUDriver EICUDriver; typedef void (*eicucallback_t)(EICUDriver *eicup, eicuchannel_t channel, uint32_t width, uint32_t period); -#include "eicu_lld.h" +#include "hal_eicu_lld.h" /*===========================================================================*/ /* Driver macros. */ diff --git a/os/hal/include/nand.h b/os/hal/include/hal_nand.h index ffd5de7..d5a1c04 100644 --- a/os/hal/include/nand.h +++ b/os/hal/include/hal_nand.h @@ -89,7 +89,7 @@ typedef enum { */ typedef struct NANDDriver NANDDriver; -#include "nand_lld.h" +#include "hal_nand_lld.h" /*===========================================================================*/ /* Driver macros. */ diff --git a/os/hal/include/onewire.h b/os/hal/include/hal_onewire.h index 2d27f48..2d27f48 100644 --- a/os/hal/include/onewire.h +++ b/os/hal/include/hal_onewire.h diff --git a/os/hal/include/rng.h b/os/hal/include/hal_rng.h index 4730f7b..4730f7b 100644 --- a/os/hal/include/rng.h +++ b/os/hal/include/hal_rng.h diff --git a/os/hal/include/timcap.h b/os/hal/include/hal_timcap.h index a848783..a848783 100644 --- a/os/hal/include/timcap.h +++ b/os/hal/include/hal_timcap.h diff --git a/os/hal/include/usbh.h b/os/hal/include/hal_usbh.h index 2f8f3dd..8029be8 100644 --- a/os/hal/include/usbh.h +++ b/os/hal/include/hal_usbh.h @@ -1,439 +1,439 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#ifndef USBH_H_
-#define USBH_H_
-
-#include "hal.h"
-
-#ifndef HAL_USE_USBH
-#define HAL_USE_USBH FALSE
-#endif
-
-#ifndef HAL_USBH_USE_FTDI
-#define HAL_USBH_USE_FTDI FALSE
-#endif
-
-#ifndef HAL_USBH_USE_HUB
-#define HAL_USBH_USE_HUB FALSE
-#endif
-
-#ifndef HAL_USBH_USE_MSD
-#define HAL_USBH_USE_MSD FALSE
-#endif
-
-#ifndef HAL_USBH_USE_UVC
-#define HAL_USBH_USE_UVC FALSE
-#endif
-
-#if HAL_USE_USBH
-
-#include "osal.h"
-#include "usbh/list.h"
-#include "usbh/defs.h"
-
-/* TODO:
- *
- * - Integrate VBUS power switching functionality to the API.
- *
- */
-
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-#if !HAL_USBH_USE_HUB
-#define USBH_MAX_ADDRESSES 1
-#else
-#define USBH_MAX_ADDRESSES (HAL_USBHHUB_MAX_PORTS + 1)
-#endif
-
-enum usbh_status {
- USBH_STATUS_STOPPED = 0,
- USBH_STATUS_STARTED,
- USBH_STATUS_SUSPENDED,
-};
-
-enum usbh_devstatus {
- USBH_DEVSTATUS_DISCONNECTED = 0,
- USBH_DEVSTATUS_ATTACHED,
- USBH_DEVSTATUS_CONNECTED,
- USBH_DEVSTATUS_DEFAULT,
- USBH_DEVSTATUS_ADDRESS,
- USBH_DEVSTATUS_CONFIGURED,
-};
-
-enum usbh_devspeed {
- USBH_DEVSPEED_LOW = 0,
- USBH_DEVSPEED_FULL,
- USBH_DEVSPEED_HIGH,
-};
-
-enum usbh_epdir {
- USBH_EPDIR_IN = 0x80,
- USBH_EPDIR_OUT = 0
-};
-
-enum usbh_eptype {
- USBH_EPTYPE_CTRL = 0,
- USBH_EPTYPE_ISO = 1,
- USBH_EPTYPE_BULK = 2,
- USBH_EPTYPE_INT = 3,
-};
-
-enum usbh_epstatus {
- USBH_EPSTATUS_UNINITIALIZED = 0,
- USBH_EPSTATUS_CLOSED,
- USBH_EPSTATUS_OPEN,
- USBH_EPSTATUS_HALTED,
-};
-
-enum usbh_urbstatus {
- USBH_URBSTATUS_UNINITIALIZED = 0,
- USBH_URBSTATUS_INITIALIZED,
- USBH_URBSTATUS_PENDING,
-// USBH_URBSTATUS_QUEUED,
- USBH_URBSTATUS_ERROR,
- USBH_URBSTATUS_TIMEOUT,
- USBH_URBSTATUS_CANCELLED,
- USBH_URBSTATUS_STALL,
- USBH_URBSTATUS_DISCONNECTED,
-// USBH_URBSTATUS_EPCLOSED,
- USBH_URBSTATUS_OK,
-};
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/* forward declarations */
-typedef struct USBHDriver USBHDriver;
-typedef struct usbh_port usbh_port_t;
-typedef struct usbh_device usbh_device_t;
-typedef struct usbh_ep usbh_ep_t;
-typedef struct usbh_urb usbh_urb_t;
-typedef struct usbh_baseclassdriver usbh_baseclassdriver_t;
-typedef struct usbh_classdriverinfo usbh_classdriverinfo_t;
-#if HAL_USBH_USE_HUB
-typedef struct USBHHubDriver USBHHubDriver;
-#endif
-
-/* typedefs */
-typedef enum usbh_status usbh_status_t;
-typedef enum usbh_devspeed usbh_devspeed_t;
-typedef enum usbh_devstatus usbh_devstatus_t;
-typedef enum usbh_epdir usbh_epdir_t;
-typedef enum usbh_eptype usbh_eptype_t;
-typedef enum usbh_epstatus usbh_epstatus_t;
-typedef enum usbh_urbstatus usbh_urbstatus_t;
-typedef uint16_t usbh_portstatus_t;
-typedef uint16_t usbh_portcstatus_t;
-typedef void (*usbh_completion_cb)(usbh_urb_t *);
-
-/* include the low level driver; the required definitions are above */
-#include "usbh_lld.h"
-
-#define USBH_DEFINE_BUFFER(type, name) USBH_LLD_DEFINE_BUFFER(type, name)
-
-struct usbh_urb {
- usbh_ep_t *ep;
-
- void *userData;
- usbh_completion_cb callback;
-
- const void *setup_buff;
- void *buff;
- uint32_t requestedLength;
- uint32_t actualLength;
-
- usbh_urbstatus_t status;
-
- thread_reference_t waitingThread;
- thread_reference_t abortingThread;
-
- /* Low level part */
- _usbh_urb_ll_data
-};
-
-struct usbh_ep {
- usbh_device_t *device;
- usbh_ep_t *next;
-
- usbh_epstatus_t status;
- uint8_t address;
- bool in;
- usbh_eptype_t type;
- uint16_t wMaxPacketSize;
- uint8_t bInterval;
-
- /* debug */
- const char *name;
-
- /* Low-level part */
- _usbh_ep_ll_data
-};
-
-struct usbh_device {
- USBHDriver *host; /* shortcut to host */
-
- usbh_ep_t ctrl;
- usbh_ep_t *endpoints;
-
- usbh_baseclassdriver_t *drivers;
-
- uint16_t langID0;
-
- usbh_devstatus_t status;
- usbh_devspeed_t speed;
-
- USBH_DEFINE_BUFFER(usbh_device_descriptor_t, devDesc);
- unsigned char align_bytes[2];
- USBH_DEFINE_BUFFER(usbh_config_descriptor_t, basicConfigDesc);
-
- uint8_t *fullConfigurationDescriptor;
- uint8_t keepFullCfgDesc;
-
- uint8_t address;
- uint8_t bConfiguration;
-
- /* Low level part */
- _usbh_device_ll_data
-};
-
-
-struct usbh_port {
-#if HAL_USBH_USE_HUB
- USBHHubDriver *hub;
-#endif
-
- usbh_portstatus_t status;
- usbh_portcstatus_t c_status;
-
- usbh_port_t *next;
-
- uint8_t number;
-
- usbh_device_t device;
-
- /* Low level part */
- _usbh_port_ll_data
-};
-
-struct USBHDriver {
- usbh_status_t status;
- uint8_t address_bitmap[(USBH_MAX_ADDRESSES + 7) / 8];
-
- usbh_port_t rootport;
-
-#if HAL_USBH_USE_HUB
- struct list_head hubs;
-#endif
-
- /* Low level part */
- _usbhdriver_ll_data
-
-#if USBH_DEBUG_ENABLE
- /* debug */
- uint8_t dbg_buff[USBH_DEBUG_BUFFER];
- THD_WORKING_AREA(waDebug, 512);
- input_queue_t iq;
-#endif
-};
-
-
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-#if STM32_USBH_USE_OTG1
-extern USBHDriver USBHD1;
-#endif
-
-#if STM32_USBH_USE_OTG2
-extern USBHDriver USBHD2;
-#endif
-
-
-/*===========================================================================*/
-/* Main driver API. */
-/*===========================================================================*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- /* Main functions */
- void usbhObjectInit(USBHDriver *usbh);
- void usbhInit(void);
- void usbhStart(USBHDriver *usbh);
- void usbhStop(USBHDriver *usbh);
- void usbhSuspend(USBHDriver *usbh);
- void usbhResume(USBHDriver *usbh);
-
- /* Device-related */
-#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO
- void usbhDevicePrintInfo(usbh_device_t *dev);
- void usbhDevicePrintConfiguration(const uint8_t *descriptor, uint16_t rem);
-#else
-# define usbhDevicePrintInfo(dev) do {} while(0)
-# define usbhDevicePrintConfiguration(descriptor, rem) do {} while(0)
-#endif
- bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size,
- uint8_t index, uint16_t langID);
- static inline usbh_port_t *usbhDeviceGetPort(usbh_device_t *dev) {
- return container_of(dev, usbh_port_t, device);
- }
-
- /* Synchronous API */
- usbh_urbstatus_t usbhBulkTransfer(usbh_ep_t *ep,
- void *data,
- uint32_t len,
- uint32_t *actual_len,
- systime_t timeout);
- usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev,
- uint8_t bmRequestType,
- uint8_t bRequest,
- uint16_t wValue,
- uint16_t wIndex,
- uint16_t wLength,
- uint8_t *buff);
- usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev,
- const usbh_control_request_t *req,
- uint8_t *buff,
- uint32_t *actual_len,
- systime_t timeout);
-
- /* Standard request helpers */
- bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev,
- uint16_t wLength,
- uint8_t *buf);
- bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev,
- uint8_t index,
- uint16_t wLength,
- uint8_t *buf);
- bool usbhStdReqGetStringDescriptor(usbh_device_t *dev,
- uint8_t index,
- uint16_t langID,
- uint16_t wLength,
- uint8_t *buf);
- bool usbhStdReqSetInterface(usbh_device_t *dev,
- uint8_t bInterfaceNumber,
- uint8_t bAlternateSetting);
- bool usbhStdReqGetInterface(usbh_device_t *dev,
- uint8_t bInterfaceNumber,
- uint8_t *bAlternateSetting);
-
- /* Endpoint/pipe management */
- void usbhEPObjectInit(usbh_ep_t *ep, usbh_device_t *dev, const usbh_endpoint_descriptor_t *desc);
- static inline void usbhEPOpen(usbh_ep_t *ep) {
- osalDbgCheck(ep != 0);
- osalSysLock();
- osalDbgAssert(ep->status == USBH_EPSTATUS_CLOSED, "invalid state");
- usbh_lld_ep_open(ep);
- ep->next = ep->device->endpoints;
- ep->device->endpoints = ep;
- osalSysUnlock();
- }
- static inline void usbhEPCloseS(usbh_ep_t *ep) {
- osalDbgCheck(ep != 0);
- osalDbgCheckClassS();
- osalDbgAssert(ep->status != USBH_EPSTATUS_UNINITIALIZED, "invalid state");
- if (ep->status == USBH_EPSTATUS_CLOSED) {
- osalOsRescheduleS();
- return;
- }
- usbh_lld_ep_close(ep);
- }
- static inline void usbhEPClose(usbh_ep_t *ep) {
- osalSysLock();
- usbhEPCloseS(ep);
- osalSysUnlock();
- }
- static inline void usbhEPResetI(usbh_ep_t *ep) {
- osalDbgCheckClassI();
- osalDbgCheck(ep != NULL);
- usbh_lld_epreset(ep);
- }
- static inline bool usbhEPIsPeriodic(usbh_ep_t *ep) {
- osalDbgCheck(ep != NULL);
- return (ep->type & 1) != 0;
- }
- static inline bool usbhURBIsBusy(usbh_urb_t *urb) {
- osalDbgCheck(urb != NULL);
- return (urb->status == USBH_URBSTATUS_PENDING);
- }
- static inline void usbhEPSetName(usbh_ep_t *ep, const char *name) {
- ep->name = name;
- }
-
- /* URB management */
- void usbhURBObjectInit(usbh_urb_t *urb, usbh_ep_t *ep, usbh_completion_cb callback,
- void *user, void *buff, uint32_t len);
- void usbhURBObjectResetI(usbh_urb_t *urb);
- void usbhURBSubmitI(usbh_urb_t *urb);
- bool usbhURBCancelI(usbh_urb_t *urb);
- msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout);
- void usbhURBCancelAndWaitS(usbh_urb_t *urb);
- msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout);
-
- /* Main loop */
- void usbhMainLoop(USBHDriver *usbh);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-/*===========================================================================*/
-/* Class driver definitions and API. */
-/*===========================================================================*/
-
-typedef struct usbh_classdriver_vmt usbh_classdriver_vmt_t;
-struct usbh_classdriver_vmt {
- usbh_baseclassdriver_t *(*load)(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
- void (*unload)(usbh_baseclassdriver_t *drv);
-};
-
-struct usbh_classdriverinfo {
- int16_t class;
- int16_t subclass;
- int16_t protocol;
- const char *name;
- const usbh_classdriver_vmt_t *vmt;
-};
-
-#define _usbh_base_classdriver_data \
- const usbh_classdriverinfo_t *info; \
- usbh_device_t *dev; \
- usbh_baseclassdriver_t *next;
-
-struct usbh_baseclassdriver {
- _usbh_base_classdriver_data
-};
-
-
-/*===========================================================================*/
-/* Helper functions. */
-/*===========================================================================*/
-#include <usbh/desciter.h> /* descriptor iterators */
-#include <usbh/debug.h> /* debug */
-
-#endif
-
-#endif /* USBH_H_ */
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef USBH_H_ +#define USBH_H_ + +#include "hal.h" + +#ifndef HAL_USE_USBH +#define HAL_USE_USBH FALSE +#endif + +#ifndef HAL_USBH_USE_FTDI +#define HAL_USBH_USE_FTDI FALSE +#endif + +#ifndef HAL_USBH_USE_HUB +#define HAL_USBH_USE_HUB FALSE +#endif + +#ifndef HAL_USBH_USE_MSD +#define HAL_USBH_USE_MSD FALSE +#endif + +#ifndef HAL_USBH_USE_UVC +#define HAL_USBH_USE_UVC FALSE +#endif + +#if HAL_USE_USBH + +#include "osal.h" +#include "usbh/list.h" +#include "usbh/defs.h" + +/* TODO: + * + * - Integrate VBUS power switching functionality to the API. + * + */ + + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !HAL_USBH_USE_HUB +#define USBH_MAX_ADDRESSES 1 +#else +#define USBH_MAX_ADDRESSES (HAL_USBHHUB_MAX_PORTS + 1) +#endif + +enum usbh_status { + USBH_STATUS_STOPPED = 0, + USBH_STATUS_STARTED, + USBH_STATUS_SUSPENDED, +}; + +enum usbh_devstatus { + USBH_DEVSTATUS_DISCONNECTED = 0, + USBH_DEVSTATUS_ATTACHED, + USBH_DEVSTATUS_CONNECTED, + USBH_DEVSTATUS_DEFAULT, + USBH_DEVSTATUS_ADDRESS, + USBH_DEVSTATUS_CONFIGURED, +}; + +enum usbh_devspeed { + USBH_DEVSPEED_LOW = 0, + USBH_DEVSPEED_FULL, + USBH_DEVSPEED_HIGH, +}; + +enum usbh_epdir { + USBH_EPDIR_IN = 0x80, + USBH_EPDIR_OUT = 0 +}; + +enum usbh_eptype { + USBH_EPTYPE_CTRL = 0, + USBH_EPTYPE_ISO = 1, + USBH_EPTYPE_BULK = 2, + USBH_EPTYPE_INT = 3, +}; + +enum usbh_epstatus { + USBH_EPSTATUS_UNINITIALIZED = 0, + USBH_EPSTATUS_CLOSED, + USBH_EPSTATUS_OPEN, + USBH_EPSTATUS_HALTED, +}; + +enum usbh_urbstatus { + USBH_URBSTATUS_UNINITIALIZED = 0, + USBH_URBSTATUS_INITIALIZED, + USBH_URBSTATUS_PENDING, +// USBH_URBSTATUS_QUEUED, + USBH_URBSTATUS_ERROR, + USBH_URBSTATUS_TIMEOUT, + USBH_URBSTATUS_CANCELLED, + USBH_URBSTATUS_STALL, + USBH_URBSTATUS_DISCONNECTED, +// USBH_URBSTATUS_EPCLOSED, + USBH_URBSTATUS_OK, +}; + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* forward declarations */ +typedef struct USBHDriver USBHDriver; +typedef struct usbh_port usbh_port_t; +typedef struct usbh_device usbh_device_t; +typedef struct usbh_ep usbh_ep_t; +typedef struct usbh_urb usbh_urb_t; +typedef struct usbh_baseclassdriver usbh_baseclassdriver_t; +typedef struct usbh_classdriverinfo usbh_classdriverinfo_t; +#if HAL_USBH_USE_HUB +typedef struct USBHHubDriver USBHHubDriver; +#endif + +/* typedefs */ +typedef enum usbh_status usbh_status_t; +typedef enum usbh_devspeed usbh_devspeed_t; +typedef enum usbh_devstatus usbh_devstatus_t; +typedef enum usbh_epdir usbh_epdir_t; +typedef enum usbh_eptype usbh_eptype_t; +typedef enum usbh_epstatus usbh_epstatus_t; +typedef enum usbh_urbstatus usbh_urbstatus_t; +typedef uint16_t usbh_portstatus_t; +typedef uint16_t usbh_portcstatus_t; +typedef void (*usbh_completion_cb)(usbh_urb_t *); + +/* include the low level driver; the required definitions are above */ +#include "hal_usbh_lld.h" + +#define USBH_DEFINE_BUFFER(type, name) USBH_LLD_DEFINE_BUFFER(type, name) + +struct usbh_urb { + usbh_ep_t *ep; + + void *userData; + usbh_completion_cb callback; + + const void *setup_buff; + void *buff; + uint32_t requestedLength; + uint32_t actualLength; + + usbh_urbstatus_t status; + + thread_reference_t waitingThread; + thread_reference_t abortingThread; + + /* Low level part */ + _usbh_urb_ll_data +}; + +struct usbh_ep { + usbh_device_t *device; + usbh_ep_t *next; + + usbh_epstatus_t status; + uint8_t address; + bool in; + usbh_eptype_t type; + uint16_t wMaxPacketSize; + uint8_t bInterval; + + /* debug */ + const char *name; + + /* Low-level part */ + _usbh_ep_ll_data +}; + +struct usbh_device { + USBHDriver *host; /* shortcut to host */ + + usbh_ep_t ctrl; + usbh_ep_t *endpoints; + + usbh_baseclassdriver_t *drivers; + + uint16_t langID0; + + usbh_devstatus_t status; + usbh_devspeed_t speed; + + USBH_DEFINE_BUFFER(usbh_device_descriptor_t, devDesc); + unsigned char align_bytes[2]; + USBH_DEFINE_BUFFER(usbh_config_descriptor_t, basicConfigDesc); + + uint8_t *fullConfigurationDescriptor; + uint8_t keepFullCfgDesc; + + uint8_t address; + uint8_t bConfiguration; + + /* Low level part */ + _usbh_device_ll_data +}; + + +struct usbh_port { +#if HAL_USBH_USE_HUB + USBHHubDriver *hub; +#endif + + usbh_portstatus_t status; + usbh_portcstatus_t c_status; + + usbh_port_t *next; + + uint8_t number; + + usbh_device_t device; + + /* Low level part */ + _usbh_port_ll_data +}; + +struct USBHDriver { + usbh_status_t status; + uint8_t address_bitmap[(USBH_MAX_ADDRESSES + 7) / 8]; + + usbh_port_t rootport; + +#if HAL_USBH_USE_HUB + struct list_head hubs; +#endif + + /* Low level part */ + _usbhdriver_ll_data + +#if USBH_DEBUG_ENABLE + /* debug */ + uint8_t dbg_buff[USBH_DEBUG_BUFFER]; + THD_WORKING_AREA(waDebug, 512); + input_queue_t iq; +#endif +}; + + + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if STM32_USBH_USE_OTG1 +extern USBHDriver USBHD1; +#endif + +#if STM32_USBH_USE_OTG2 +extern USBHDriver USBHD2; +#endif + + +/*===========================================================================*/ +/* Main driver API. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + + /* Main functions */ + void usbhObjectInit(USBHDriver *usbh); + void usbhInit(void); + void usbhStart(USBHDriver *usbh); + void usbhStop(USBHDriver *usbh); + void usbhSuspend(USBHDriver *usbh); + void usbhResume(USBHDriver *usbh); + + /* Device-related */ +#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO + void usbhDevicePrintInfo(usbh_device_t *dev); + void usbhDevicePrintConfiguration(const uint8_t *descriptor, uint16_t rem); +#else +# define usbhDevicePrintInfo(dev) do {} while(0) +# define usbhDevicePrintConfiguration(descriptor, rem) do {} while(0) +#endif + bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size, + uint8_t index, uint16_t langID); + static inline usbh_port_t *usbhDeviceGetPort(usbh_device_t *dev) { + return container_of(dev, usbh_port_t, device); + } + + /* Synchronous API */ + usbh_urbstatus_t usbhBulkTransfer(usbh_ep_t *ep, + void *data, + uint32_t len, + uint32_t *actual_len, + systime_t timeout); + usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev, + uint8_t bmRequestType, + uint8_t bRequest, + uint16_t wValue, + uint16_t wIndex, + uint16_t wLength, + uint8_t *buff); + usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev, + const usbh_control_request_t *req, + uint8_t *buff, + uint32_t *actual_len, + systime_t timeout); + + /* Standard request helpers */ + bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev, + uint16_t wLength, + uint8_t *buf); + bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev, + uint8_t index, + uint16_t wLength, + uint8_t *buf); + bool usbhStdReqGetStringDescriptor(usbh_device_t *dev, + uint8_t index, + uint16_t langID, + uint16_t wLength, + uint8_t *buf); + bool usbhStdReqSetInterface(usbh_device_t *dev, + uint8_t bInterfaceNumber, + uint8_t bAlternateSetting); + bool usbhStdReqGetInterface(usbh_device_t *dev, + uint8_t bInterfaceNumber, + uint8_t *bAlternateSetting); + + /* Endpoint/pipe management */ + void usbhEPObjectInit(usbh_ep_t *ep, usbh_device_t *dev, const usbh_endpoint_descriptor_t *desc); + static inline void usbhEPOpen(usbh_ep_t *ep) { + osalDbgCheck(ep != 0); + osalSysLock(); + osalDbgAssert(ep->status == USBH_EPSTATUS_CLOSED, "invalid state"); + usbh_lld_ep_open(ep); + ep->next = ep->device->endpoints; + ep->device->endpoints = ep; + osalSysUnlock(); + } + static inline void usbhEPCloseS(usbh_ep_t *ep) { + osalDbgCheck(ep != 0); + osalDbgCheckClassS(); + osalDbgAssert(ep->status != USBH_EPSTATUS_UNINITIALIZED, "invalid state"); + if (ep->status == USBH_EPSTATUS_CLOSED) { + osalOsRescheduleS(); + return; + } + usbh_lld_ep_close(ep); + } + static inline void usbhEPClose(usbh_ep_t *ep) { + osalSysLock(); + usbhEPCloseS(ep); + osalSysUnlock(); + } + static inline void usbhEPResetI(usbh_ep_t *ep) { + osalDbgCheckClassI(); + osalDbgCheck(ep != NULL); + usbh_lld_epreset(ep); + } + static inline bool usbhEPIsPeriodic(usbh_ep_t *ep) { + osalDbgCheck(ep != NULL); + return (ep->type & 1) != 0; + } + static inline bool usbhURBIsBusy(usbh_urb_t *urb) { + osalDbgCheck(urb != NULL); + return (urb->status == USBH_URBSTATUS_PENDING); + } + static inline void usbhEPSetName(usbh_ep_t *ep, const char *name) { + ep->name = name; + } + + /* URB management */ + void usbhURBObjectInit(usbh_urb_t *urb, usbh_ep_t *ep, usbh_completion_cb callback, + void *user, void *buff, uint32_t len); + void usbhURBObjectResetI(usbh_urb_t *urb); + void usbhURBSubmitI(usbh_urb_t *urb); + bool usbhURBCancelI(usbh_urb_t *urb); + msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout); + void usbhURBCancelAndWaitS(usbh_urb_t *urb); + msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout); + + /* Main loop */ + void usbhMainLoop(USBHDriver *usbh); + +#ifdef __cplusplus +} +#endif + + +/*===========================================================================*/ +/* Class driver definitions and API. */ +/*===========================================================================*/ + +typedef struct usbh_classdriver_vmt usbh_classdriver_vmt_t; +struct usbh_classdriver_vmt { + usbh_baseclassdriver_t *(*load)(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); + void (*unload)(usbh_baseclassdriver_t *drv); +}; + +struct usbh_classdriverinfo { + int16_t class; + int16_t subclass; + int16_t protocol; + const char *name; + const usbh_classdriver_vmt_t *vmt; +}; + +#define _usbh_base_classdriver_data \ + const usbh_classdriverinfo_t *info; \ + usbh_device_t *dev; \ + usbh_baseclassdriver_t *next; + +struct usbh_baseclassdriver { + _usbh_base_classdriver_data +}; + + +/*===========================================================================*/ +/* Helper functions. */ +/*===========================================================================*/ +#include <usbh/desciter.h> /* descriptor iterators */ +#include <usbh/debug.h> /* debug */ + +#endif + +#endif /* USBH_H_ */ diff --git a/os/hal/include/usbh/debug.h b/os/hal/include/usbh/debug.h index 219eeb1..5120121 100644 --- a/os/hal/include/usbh/debug.h +++ b/os/hal/include/usbh/debug.h @@ -19,7 +19,7 @@ #ifndef USBH_DEBUG_H_
#define USBH_DEBUG_H_
-#include "usbh.h"
+#include "hal_usbh.h"
#if HAL_USE_USBH
diff --git a/os/hal/include/usbh/dev/ftdi.h b/os/hal/include/usbh/dev/ftdi.h index 678a521..ad6b4cd 100644 --- a/os/hal/include/usbh/dev/ftdi.h +++ b/os/hal/include/usbh/dev/ftdi.h @@ -18,7 +18,7 @@ #ifndef USBH_FTDI_H_
#define USBH_FTDI_H_
-#include "usbh.h"
+#include "hal_usbh.h"
#if HAL_USE_USBH && HAL_USBH_USE_FTDI
diff --git a/os/hal/include/usbh/dev/hub.h b/os/hal/include/usbh/dev/hub.h index 28a0681..07e88e6 100644 --- a/os/hal/include/usbh/dev/hub.h +++ b/os/hal/include/usbh/dev/hub.h @@ -18,7 +18,7 @@ #ifndef USBH_HUB_H_
#define USBH_HUB_H_
-#include "usbh.h"
+#include "hal_usbh.h"
#if HAL_USE_USBH
#if HAL_USBH_USE_HUB
diff --git a/os/hal/include/usbh/dev/msd.h b/os/hal/include/usbh/dev/msd.h index 2ca8817..d164618 100644 --- a/os/hal/include/usbh/dev/msd.h +++ b/os/hal/include/usbh/dev/msd.h @@ -18,7 +18,7 @@ #ifndef USBH_MSD_H_
#define USBH_MSD_H_
-#include "usbh.h"
+#include "hal_usbh.h"
#if HAL_USE_USBH && HAL_USBH_USE_MSD
diff --git a/os/hal/include/usbh/internal.h b/os/hal/include/usbh/internal.h index 6811e20..baa477f 100644 --- a/os/hal/include/usbh/internal.h +++ b/os/hal/include/usbh/internal.h @@ -18,7 +18,7 @@ #ifndef USBH_INTERNAL_H_
#define USBH_INTERNAL_H_
-#include "usbh.h"
+#include "hal_usbh.h"
#if HAL_USE_USBH
diff --git a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c index 601deca..601deca 100644 --- a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c +++ b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c diff --git a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.h b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h index ecdaf81..ecdaf81 100644 --- a/os/hal/ports/STM32/LLD/CRCv1/crc_lld.h +++ b/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.h diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c index 977eba0..aba029f 100644 --- a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c +++ b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c @@ -1,3130 +1,3130 @@ -/*
- Copyright (C) 2013-2015 Andrea Zoppi
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file stm32_dma2d.c
- * @brief DMA2D/Chrom-ART driver.
- */
-
-#include "ch.h"
-#include "hal.h"
-
-#include "stm32_dma2d.h"
-
-#if STM32_DMA2D_USE_DMA2D || defined(__DOXYGEN__)
-
-/* Ignore annoying warning messages for actually safe code.*/
-#if defined(__GNUC__) && !defined(__DOXYGEN__)
-#pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-
-/**
- * @addtogroup dma2d
- * @{
- */
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/** @brief DMA2DD1 driver identifier.*/
-DMA2DDriver DMA2DD1;
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief Bits per pixel lookup table.
- */
-static const uint8_t dma2d_bpp[DMA2D_MAX_PIXFMT_ID + 1] = {
- 32, /* DMA2D_FMT_ARGB8888 */
- 24, /* DMA2D_FMT_RGB888 */
- 16, /* DMA2D_FMT_RGB565 */
- 16, /* DMA2D_FMT_ARGB1555 */
- 16, /* DMA2D_FMT_ARGB4444 */
- 8, /* DMA2D_FMT_L8 */
- 8, /* DMA2D_FMT_AL44 */
- 16, /* DMA2D_FMT_AL88 */
- 4, /* DMA2D_FMT_L4 */
- 8, /* DMA2D_FMT_A8 */
- 4 /* DMA2D_FMT_A4 */
-};
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @name DMA2D interrupt handlers
- * @{
- */
-
-/**
- * @brief DMA2D global interrupt handler.
- *
- * @isr
- */
-OSAL_IRQ_HANDLER(STM32_DMA2D_HANDLER) {
-
- DMA2DDriver *const dma2dp = &DMA2DD1;
- bool job_done = false;
- thread_t *tp = NULL;
-
- OSAL_IRQ_PROLOGUE();
-
- /* Handle Configuration Error ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_CEIF) && (DMA2D->CR & DMA2D_CR_CEIE)) {
- if (dma2dp->config->cfgerr_isr != NULL)
- dma2dp->config->cfgerr_isr(dma2dp);
- job_done = true;
- DMA2D->IFCR |= DMA2D_IFSR_CCEIF;
- }
-
- /* Handle CLUT (Palette) Transfer Complete ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_CTCIF) && (DMA2D->CR & DMA2D_CR_CTCIE)) {
- if (dma2dp->config->paltrfdone_isr != NULL)
- dma2dp->config->paltrfdone_isr(dma2dp);
- job_done = true;
- DMA2D->IFCR |= DMA2D_IFSR_CCTCIF;
- }
-
- /* Handle CLUT (Palette) Access Error ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_CAEIF) && (DMA2D->CR & DMA2D_CR_CAEIE)) {
- if (dma2dp->config->palacserr_isr != NULL)
- dma2dp->config->palacserr_isr(dma2dp);
- job_done = true;
- DMA2D->IFCR |= DMA2D_IFSR_CCAEIF;
- }
-
- /* Handle Transfer Watermark ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_TWIF) && (DMA2D->CR & DMA2D_CR_TWIE)) {
- if (dma2dp->config->trfwmark_isr != NULL)
- dma2dp->config->trfwmark_isr(dma2dp);
- DMA2D->IFCR |= DMA2D_IFSR_CTWIF;
- }
-
- /* Handle Transfer Complete ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_TCIF) && (DMA2D->CR & DMA2D_CR_TCIE)) {
- if (dma2dp->config->trfdone_isr != NULL)
- dma2dp->config->trfdone_isr(dma2dp);
- job_done = true;
- DMA2D->IFCR |= DMA2D_IFSR_CTCIF;
- }
-
- /* Handle Transfer Error ISR.*/
- if ((DMA2D->ISR & DMA2D_ISR_TEIF) && (DMA2D->CR & DMA2D_CR_TEIE)) {
- if (dma2dp->config->trferr_isr != NULL)
- dma2dp->config->trferr_isr(dma2dp);
- job_done = true;
- DMA2D->IFCR |= DMA2D_IFSR_CTEIF;
- }
-
- if (job_done) {
- osalSysLockFromISR();
- osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state");
-
- #if DMA2D_USE_WAIT
- /* Wake the waiting thread up.*/
- if (dma2dp->thread != NULL) {
- tp = dma2dp->thread;
- dma2dp->thread = NULL;
- tp->u.rdymsg = MSG_OK;
- chSchReadyI(tp);
- }
- #endif /* DMA2D_USE_WAIT */
-
- dma2dp->state = DMA2D_READY;
- osalSysUnlockFromISR();
- }
-
- OSAL_IRQ_EPILOGUE();
-}
-
-/** @} */
-
-/**
- * @name DMA2D driver-specific methods
- * @{
- */
-
-/**
- * @brief DMA2D Driver initialization.
- * @details Initializes the DMA2D subsystem and chosen drivers. Should be
- * called at board initialization.
- *
- * @init
- */
-void dma2dInit(void) {
-
- /* Reset the DMA2D hardware module.*/
- rccResetDMA2D();
-
- /* Enable the DMA2D clock.*/
- rccEnableDMA2D(false);
-
- /* Driver struct initialization.*/
- dma2dObjectInit(&DMA2DD1);
- DMA2DD1.state = DMA2D_STOP;
-}
-
-/**
- * @brief Initializes the standard part of a @p DMA2DDriver structure.
- *
- * @param[out] dma2dp pointer to the @p DMA2DDriver object
- *
- * @init
- */
-void dma2dObjectInit(DMA2DDriver *dma2dp) {
-
- osalDbgCheck(dma2dp == &DMA2DD1);
-
- dma2dp->state = DMA2D_UNINIT;
- dma2dp->config = NULL;
-#if DMA2D_USE_WAIT
- dma2dp->thread = NULL;
-#endif /* DMA2D_USE_WAIT */
-#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION)
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxObjectInit(&dma2dp->lock);
-#else
- chSemObjectInit(&dma2dp->lock, 1);
-#endif
-#endif /* (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) */
-}
-
-/**
- * @brief Get the driver state.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @retun driver state
- *
- * @iclass
- */
-dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp) {
-
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheckClassI();
-
- return dma2dp->state;
-}
-
-/**
- * @brief Get the driver state.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @retun driver state
- *
- * @api
- */
-dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp) {
-
- dma2d_state_t state;
- chSysLock();
- state = dma2dGetStateI(dma2dp);
- chSysUnlock();
- return state;
-}
-
-/**
- * @brief Configures and activates the DMA2D peripheral.
- * @pre DMA2D is stopped.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] configp pointer to the @p DMA2DConfig object
- *
- * @api
- */
-void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp) {
-
- chSysLock();
-
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(configp != NULL);
- osalDbgAssert(dma2dp->state == DMA2D_STOP, "invalid state");
-
- dma2dp->config = configp;
-
- /* Turn off the controller and its interrupts.*/
- DMA2D->CR = 0;
-
- /* Enable interrupts, except Line Watermark.*/
- nvicEnableVector(STM32_DMA2D_NUMBER, STM32_DMA2D_IRQ_PRIORITY);
-
- DMA2D->CR = (DMA2D_CR_CEIE | DMA2D_CR_CTCIE | DMA2D_CR_CAEIE |
- DMA2D_CR_TCIE | DMA2D_CR_TEIE);
-
- dma2dp->state = DMA2D_READY;
- chSysUnlock();
-}
-
-/**
- * @brief Deactivates the DMA2D peripheral.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dStop(DMA2DDriver *dma2dp) {
-
- chSysLock();
-
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "invalid state");
-#if DMA2D_USE_WAIT
- osalDbgAssert(dma2dp->thread == NULL, "still waiting");
-#endif /* DMA2D_USE_WAIT */
-
- dma2dp->state = DMA2D_STOP;
- chSysUnlock();
-}
-
-#if DMA2D_USE_MUTUAL_EXCLUSION
-
-/**
- * @brief Gains exclusive access to the DMA2D module.
- * @details This function tries to gain ownership to the DMA2D module, if the
- * module is already being used then the invoking thread is queued.
- * @pre In order to use this function the option
- * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @sclass
- */
-void dma2dAcquireBusS(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
-
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxLockS(&dma2dp->lock);
-#else
- chSemWaitS(&dma2dp->lock);
-#endif
-}
-
-/**
- * @brief Gains exclusive access to the DMA2D module.
- * @details This function tries to gain ownership to the DMA2D module, if the
- * module is already being used then the invoking thread is queued.
- * @pre In order to use this function the option
- * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dAcquireBus(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dAcquireBusS(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Releases exclusive access to the DMA2D module.
- * @pre In order to use this function the option
- * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @sclass
- */
-void dma2dReleaseBusS(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
-
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxUnlockS(&dma2dp->lock);
-#else
- chSemSignalI(&dma2dp->lock);
-#endif
-}
-
-/**
- * @brief Releases exclusive access to the DMA2D module.
- * @pre In order to use this function the option
- * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dReleaseBus(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dReleaseBusS(dma2dp);
- chSysUnlock();
-}
-
-#endif /* DMA2D_USE_MUTUAL_EXCLUSION */
-
-/** @} */
-
-/**
- * @name DMA2D global methods
- * @{
- */
-
-/**
- * @brief Get watermark position.
- * @details Gets the watermark line position.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return watermark line position
- *
- * @iclass
- */
-uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (uint16_t)(DMA2D->LWR & DMA2D_LWR_LW);
-}
-
-/**
- * @brief Get watermark position.
- * @details Gets the watermark line position.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return watermark line position
- *
- * @api
- */
-uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp) {
-
- uint16_t line;
- chSysLock();
- line = dma2dGetWatermarkPosI(dma2dp);
- chSysUnlock();
- return line;
-}
-
-/**
- * @brief Set watermark position.
- * @details Sets the watermark line position.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] line watermark line position
- *
- * @iclass
- */
-void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->LWR = ((DMA2D->LWR & ~DMA2D_LWR_LW) |
- ((uint32_t)line & DMA2D_LWR_LW));
-}
-
-/**
- * @brief Set watermark position.
- * @details Sets the watermark line position.
- * @note The interrupt is invoked after the last pixel of the watermark line
- * is written.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] line watermark line position
- *
- * @iclass
- */
-void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line) {
-
- chSysLock();
- dma2dSetWatermarkPosI(dma2dp, line);
- chSysUnlock();
-}
-
-/**
- * @brief Watermark interrupt enabled.
- * @details Tells whether the watermark interrupt is enabled.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (DMA2D->CR & DMA2D_CR_TWIE) != 0;
-}
-
-/**
- * @brief Watermark interrupt enabled.
- * @details Tells whether the watermark interrupt is enabled.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp) {
-
- bool enabled;
- chSysLock();
- enabled = dma2dIsWatermarkEnabledI(dma2dp);
- chSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable watermark interrupt.
- * @details Enables the watermark interrupt. The interrupt is invoked after the
- * last pixel of the watermark line is written to the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dEnableWatermarkI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- DMA2D->CR |= DMA2D_CR_TWIE;
-}
-
-/**
- * @brief Enable watermark interrupt.
- * @details Enables the watermark interrupt. The interrupt is invoked after the
- * last pixel of the watermark line is written to the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dEnableWatermark(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dEnableWatermarkI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Disable watermark interrupt.
- * @details Disables the watermark interrupt.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dDisableWatermarkI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- DMA2D->CR &= ~DMA2D_CR_TWIE;
-}
-
-/**
- * @brief Disable watermark interrupt.
- * @details Disables the watermark interrupt.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dDisableWatermark(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dDisableWatermarkI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Get dead time cycles.
- * @details Gets the minimum dead time DMA2D clock cycles between DMA2D
- * transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return dead time, in DMA2D clock cycles
- *
- * @iclass
- */
-uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (DMA2D->AMTCR & DMA2D_AMTCR_DT) >> 8;
-}
-
-/**
- * @brief Get dead time cycles.
- * @details Gets the minimum dead time DMA2D clock cycles between DMA2D
- * transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return dead time, in DMA2D clock cycles
- *
- * @api
- */
-uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp) {
-
- uint32_t cycles;
- chSysLock();
- cycles = dma2dGetDeadTimeI(dma2dp);
- chSysUnlock();
- return cycles;
-}
-
-/**
- * @brief Set dead time cycles.
- * @details Sets the minimum dead time DMA2D clock cycles between DMA2D
- * transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cycles dead time, in DMA2D clock cycles
- *
- * @iclass
- */
-void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(cycles <= DMA2D_MAX_DEADTIME_CYCLES, "bounds");
- (void)dma2dp;
-
- DMA2D->AMTCR = ((DMA2D->AMTCR & ~DMA2D_AMTCR_DT) |
- ((cycles << 8) & DMA2D_AMTCR_DT));
-}
-
-/**
- * @brief Set dead time cycles.
- * @details Sets the minimum dead time DMA2D clock cycles between DMA2D
- * transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cycles dead time, in DMA2D clock cycles
- *
- * @api
- */
-void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles) {
-
- chSysLock();
- dma2dSetDeadTimeI(dma2dp, cycles);
- chSysUnlock();
-}
-
-/**
- * @brief Dead time enabled.
- * @details Tells whether the dead time between DMA2D transactions is enabled.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (DMA2D->AMTCR & DMA2D_AMTCR_EN) != 0;
-}
-
-/**
- * @brief Dead time enabled.
- * @details Tells whether the dead time between DMA2D transactions is enabled.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp) {
-
- bool enabled;
- chSysLock();
- enabled = dma2dIsDeadTimeEnabledI(dma2dp);
- chSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable dead time.
- * @details Enables the dead time between DMA2D transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- DMA2D->AMTCR |= DMA2D_AMTCR_EN;
-}
-
-/**
- * @brief Enable dead time.
- * @details Enables the dead time between DMA2D transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dEnableDeadTime(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dEnableDeadTimeI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Disable dead time.
- * @details Disables the dead time between DMA2D transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- DMA2D->AMTCR &= ~DMA2D_AMTCR_EN;
-}
-
-/**
- * @brief Disable dead time.
- * @details Disables the dead time between DMA2D transactions.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dDisableDeadTime(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dDisableDeadTimeI(dma2dp);
- chSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name DMA2D job (transaction) methods
- * @{
- */
-
-/**
- * @brief Get job mode.
- * @details Gets the job mode.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return job mode
- *
- * @iclass
- */
-dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_jobmode_t)(DMA2D->CR & DMA2D_CR_MODE);
-}
-
-/**
- * @brief Get job mode.
- * @details Gets the job mode.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return job mode
- *
- * @api
- */
-dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp) {
-
- dma2d_jobmode_t mode;
- chSysLock();
- mode = dma2dJobGetModeI(dma2dp);
- chSysUnlock();
- return mode;
-}
-
-/**
- * @brief Set job mode.
- * @details Sets the job mode.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode job mode
- *
- * @iclass
- */
-void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert((mode & ~DMA2D_CR_MODE) == 0, "bounds");
- (void)dma2dp;
-
- DMA2D->CR = ((DMA2D->CR & ~DMA2D_CR_MODE) |
- ((uint32_t)mode & DMA2D_CR_MODE));
-}
-
-/**
- * @brief Set job mode.
- * @details Sets the job mode.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode job mode
- *
- * @api
- */
-void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) {
-
- chSysLock();
- dma2dJobSetModeI(dma2dp, mode);
- chSysUnlock();
-}
-
-/**
- * @brief Get job size.
- * @details Gets the job size.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] widthp pointer to the job width, in pixels
- * @param[out] heightp pointer to the job height, in pixels
- *
- * @iclass
- */
-void dma2dJobGetSizeI(DMA2DDriver *dma2dp,
- uint16_t *widthp, uint16_t *heightp) {
-
- uint32_t r;
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(widthp != NULL);
- osalDbgCheck(heightp != NULL);
- (void)dma2dp;
-
- r = DMA2D->NLR;
- *widthp = (uint16_t)((r & DMA2D_NLR_PL) >> 16);
- *heightp = (uint16_t)((r & DMA2D_NLR_NL) >> 0);
-}
-
-/**
- * @brief Get job size.
- * @details Gets the job size.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] widthp pointer to the job width, in pixels
- * @param[out] heightp pointer to the job height, in pixels
- *
- * @api
- */
-void dma2dJobGetSize(DMA2DDriver *dma2dp,
- uint16_t *widthp, uint16_t *heightp) {
-
- chSysLock();
- dma2dJobGetSizeI(dma2dp, widthp, heightp);
- chSysUnlock();
-}
-
-/**
- * @brief Set job size.
- * @details Sets the job size.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] widthp job width, in pixels
- * @param[in] heightp job height, in pixels
- *
- * @iclass
- */
-void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(width <= DMA2D_MAX_WIDTH, "bounds");
- osalDbgAssert(height <= DMA2D_MAX_HEIGHT, "bounds");
- (void)dma2dp;
-
- DMA2D->NLR = ((((uint32_t)width << 16) & DMA2D_NLR_PL) |
- (((uint32_t)height << 0) & DMA2D_NLR_NL));
-}
-
-/**
- * @brief Set job size.
- * @details Sets the job size.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] widthp job width, in pixels
- * @param[in] heightp job height, in pixels
- *
- * @api
- */
-void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) {
-
- chSysLock();
- dma2dJobSetSizeI(dma2dp, width, height);
- chSysUnlock();
-}
-
-/**
- * @brief Job executing.
- * @details Tells whether a job (transaction) is active or paused.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return executing
- *
- * @iclass
- */
-bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
-
- return dma2dp->state > DMA2D_READY;
-}
-
-/**
- * @brief Job executing.
- * @details Tells whether a job (transaction) is active or paused.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return executing
- *
- * @api
- */
-bool dma2dJobIsExecuting(DMA2DDriver *dma2dp) {
-
- bool executing;
- chSysLock();
- executing = dma2dJobIsExecutingI(dma2dp);
- chSysUnlock();
- return executing;
-}
-
-/**
- * @brief Start job.
- * @details The job is started, and the DMA2D is set to active.
- * @note Should there be invalid parameters, the appropriate interrupt
- * handler will be invoked, and the DMA2D set back to ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dJobStartI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
-
- dma2dp->state = DMA2D_ACTIVE;
- DMA2D->CR |= DMA2D_CR_START;
-}
-
-/**
- * @brief Start job.
- * @details The job is started, and the DMA2D is set to active.
- * @note Should there be invalid parameters, the appropriate interrupt
- * handler will be invoked, and the DMA2D set back to ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dJobStart(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dJobStartI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Execute job.
- * @details Starts the job and waits for its completion, synchronously.
- * @note Should there be invalid parameters, the appropriate interrupt
- * handler will be invoked, and the DMA2D set back to ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @sclass
- */
-void dma2dJobExecuteS(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
-
- dma2dJobStartI(dma2dp);
-#if DMA2D_USE_WAIT
- dma2dp->thread = chThdGetSelfX();
- chSchGoSleepS(CH_STATE_SUSPENDED);
-#else
- while (DMA2D->CR & DMA2D_CR_START)
- chSchDoYieldS();
-#endif
-}
-
-/**
- * @brief Execute job.
- * @details Starts the job and waits for its completion, synchronously.
- * @note Should there be invalid parameters, the appropriate interrupt
- * handler will be invoked, and the DMA2D set back to ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dJobExecute(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dJobExecuteS(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Suspend current job.
- * @details Suspends the current job. The driver is set to a paused state.
- * @pre There is an active job.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dJobSuspendI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0);
- osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state");
-
- dma2dp->state = DMA2D_PAUSED;
- DMA2D->CR |= DMA2D_CR_SUSP;
-}
-
-/**
- * @brief Suspend current job.
- * @details Suspends the current job. The driver is set to a paused state.
- * @pre There is an active job.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dJobSuspend(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dJobSuspendI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Resume current job.
- * @details Resumes the current job.
- * @pre There is a paused job.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dJobResumeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) != 0);
- osalDbgAssert(dma2dp->state == DMA2D_PAUSED, "invalid state");
-
- dma2dp->state = DMA2D_ACTIVE;
- DMA2D->CR &= ~DMA2D_CR_SUSP;
-}
-
-/**
- * @brief Resume current job.
- * @details Resumes the current job.
- * @pre There is a paused job.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dJobResume(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dJobResumeI(dma2dp);
- chSysUnlock();
-}
-
-/**
- * @brief Abort current job.
- * @details Abots the current job (if any), and the driver becomes ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @iclass
- */
-void dma2dJobAbortI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0);
- osalDbgAssert(dma2dp->state >= DMA2D_READY, "invalid state");
-
- dma2dp->state = DMA2D_READY;
- DMA2D->CR |= DMA2D_CR_ABORT;
-}
-
-/**
- * @brief Abort current job.
- * @details Abots the current job (if any), and the driver becomes ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @api
- */
-void dma2dJobAbort(DMA2DDriver *dma2dp) {
-
- chSysLock();
- dma2dJobAbortI(dma2dp);
- chSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name DMA2D background layer methods
- * @{
- */
-
-/**
- * @brief Get background layer buffer address.
- * @details Gets the buffer address of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @iclass
- */
-void *dma2dBgGetAddressI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (void *)DMA2D->BGMAR;
-}
-
-/**
- * @brief Get background layer buffer address.
- * @details Gets the buffer address of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @api
- */
-void *dma2dBgGetAddress(DMA2DDriver *dma2dp) {
-
- void *bufferp;
- chSysLock();
- bufferp = dma2dBgGetAddressI(dma2dp);
- chSysUnlock();
- return bufferp;
-}
-
-/**
- * @brief Set background layer buffer address.
- * @details Sets the buffer address of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @iclass
- */
-void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(dma2dIsAligned(bufferp, dma2dBgGetPixelFormatI(dma2dp)));
- (void)dma2dp;
-
- DMA2D->BGMAR = (uint32_t)bufferp;
-}
-
-/**
- * @brief Set background layer buffer address.
- * @details Sets the buffer address of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @api
- */
-void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp) {
-
- chSysLock();
- dma2dBgSetAddressI(dma2dp, bufferp);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer wrap offset.
- * @details Gets the buffer line wrap offset of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @iclass
- */
-size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (size_t)(DMA2D->BGOR & DMA2D_BGOR_LO);
-}
-
-/**
- * @brief Get background layer wrap offset.
- * @details Gets the buffer line wrap offset of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @api
- */
-size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp) {
-
- size_t offset;
- chSysLock();
- offset = dma2dBgGetWrapOffsetI(dma2dp);
- chSysUnlock();
- return offset;
-}
-
-/**
- * @brief Set background layer wrap offset.
- * @details Sets the buffer line wrap offset of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @iclass
- */
-void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds");
- (void)dma2dp;
-
- DMA2D->BGOR = ((DMA2D->BGOR & ~DMA2D_BGOR_LO) |
- ((uint32_t)offset & DMA2D_BGOR_LO));
-}
-
-/**
- * @brief Set background layer wrap offset.
- * @details Sets the buffer line wrap offset of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @api
- */
-void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) {
-
- chSysLock();
- dma2dBgSetWrapOffsetI(dma2dp, offset);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer constant alpha.
- * @details Gets the constant alpha component of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return constant alpha component, A-8
- *
- * @iclass
- */
-uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (uint8_t)((DMA2D->BGPFCCR & DMA2D_BGPFCCR_ALPHA) >> 24);
-}
-
-/**
- * @brief Get background layer constant alpha.
- * @details Gets the constant alpha component of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return constant alpha component, A-8
- *
- * @api
- */
-uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp) {
-
- uint8_t a;
- chSysLock();
- a = dma2dBgGetConstantAlphaI(dma2dp);
- chSysUnlock();
- return a;
-}
-
-/**
- * @brief Set background layer constant alpha.
- * @details Sets the constant alpha component of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @iclass
- */
-void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_ALPHA) |
- (((uint32_t)a << 24) & DMA2D_BGPFCCR_ALPHA));
-}
-
-/**
- * @brief Set background layer constant alpha.
- * @details Sets the constant alpha component of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @api
- */
-void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) {
-
- chSysLock();
- dma2dBgSetConstantAlphaI(dma2dp, a);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer alpha mode.
- * @details Gets the alpha mode of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return alpha mode
- *
- * @iclass
- */
-dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_amode_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_AM);
-}
-
-/**
- * @brief Get background layer alpha mode.
- * @details Gets the alpha mode of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return alpha mode
- *
- * @api
- */
-dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp) {
-
- dma2d_amode_t mode;
- chSysLock();
- mode = dma2dBgGetAlphaModeI(dma2dp);
- chSysUnlock();
- return mode;
-}
-
-/**
- * @brief Set background layer alpha mode.
- * @details Sets the alpha mode of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode alpha mode
- *
- * @iclass
- */
-void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert((mode & ~DMA2D_BGPFCCR_AM) == 0, "bounds");
- osalDbgAssert((mode & DMA2D_BGPFCCR_AM) != DMA2D_BGPFCCR_AM, "bounds");
- (void)dma2dp;
-
- DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_AM) |
- ((uint32_t)mode & DMA2D_BGPFCCR_AM));
-}
-
-/**
- * @brief Set background layer alpha mode.
- * @details Sets the alpha mode of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode alpha mode
- *
- * @api
- */
-void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) {
-
- chSysLock();
- dma2dBgSetAlphaModeI(dma2dp, mode);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer pixel format.
- * @details Gets the pixel format of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @iclass
- */
-dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_pixfmt_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_CM);
-}
-
-/**
- * @brief Get background layer pixel format.
- * @details Gets the pixel format of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @api
- */
-dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp) {
-
- dma2d_pixfmt_t fmt;
- chSysLock();
- fmt = dma2dBgGetPixelFormatI(dma2dp);
- chSysUnlock();
- return fmt;
-}
-
-/**
- * @brief Set background layer pixel format.
- * @details Sets the pixel format of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @iclass
- */
-void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds");
- (void)dma2dp;
-
- DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_CM) |
- ((uint32_t)fmt & DMA2D_BGPFCCR_CM));
-}
-
-/**
- * @brief Set background layer pixel format.
- * @details Sets the pixel format of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @api
- */
-void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- chSysLock();
- dma2dBgSetPixelFormatI(dma2dp, fmt);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer default color.
- * @details Gets the default color of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, RGB-888
- *
- * @iclass
- */
-dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_color_t)(DMA2D->BGCOLR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get background layer default color.
- * @details Gets the default color of the background layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, RGB-888
- *
- * @api
- */
-dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp) {
-
- dma2d_color_t c;
- chSysLock();
- c = dma2dBgGetDefaultColorI(dma2dp);
- chSysUnlock();
- return c;
-}
-
-/**
- * @brief Set background layer default color.
- * @details Sets the default color of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, RGB-888
- *
- * @iclass
- */
-void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->BGCOLR = (uint32_t)c & 0x00FFFFFF;
-}
-
-/**
- * @brief Set background layer default color.
- * @details Sets the default color of the background layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, RGB-888
- *
- * @api
- */
-void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- chSysLock();
- dma2dBgSetDefaultColorI(dma2dp, c);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer palette specifications.
- * @details Gets the palette specifications of the background layer.
- * @note The palette colors pointer is actually addressed to a @p volatile
- * memory zone.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] palettep pointer to the palette specifications
- *
- * @iclass
- */
-void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) {
-
- uint32_t r;
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(palettep != NULL);
- (void)dma2dp;
-
- r = DMA2D->BGPFCCR;
- palettep->colorsp = (const void *)DMA2D->BGCLUT;
- palettep->length = (uint16_t)((r & DMA2D_BGPFCCR_CS) >> 8) + 1;
- palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_BGPFCCR_CCM) >> 4);
-}
-
-/**
- * @brief Get background layer palette specifications.
- * @details Gets the palette specifications of the background layer.
- * @note The palette colors pointer is actually addressed to a @p volatile
- * memory zone.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] palettep pointer to the palette specifications
- *
- * @api
- */
-void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) {
-
- chSysLock();
- dma2dBgGetPaletteI(dma2dp, palettep);
- chSysUnlock();
-}
-
-/**
- * @brief Set background layer palette specifications.
- * @details Sets the palette specifications of the background layer.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] palettep pointer to the palette specifications
- *
- * @sclass
- */
-void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(palettep != NULL);
- osalDbgCheck(palettep->colorsp != NULL);
- osalDbgAssert(palettep->length > 0, "bounds");
- osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds");
- osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) ||
- (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format");
-
- DMA2D->BGCMAR = (uint32_t)palettep->colorsp;
- DMA2D->BGPFCCR = (
- (DMA2D->BGPFCCR & ~(DMA2D_BGPFCCR_CS | DMA2D_BGPFCCR_CCM)) |
- ((((uint32_t)palettep->length - 1) << 8) & DMA2D_BGPFCCR_CS) |
- ((uint32_t)palettep->fmt << 4)
- );
-
- dma2dp->state = DMA2D_ACTIVE;
- DMA2D->BGPFCCR |= DMA2D_BGPFCCR_START;
-
-#if DMA2D_USE_WAIT
- dma2dp->thread = chThdGetSelfX();
- chSchGoSleepS(CH_STATE_SUSPENDED);
-#else
- while (DMA2D->BGPFCCR & DMA2D_BGPFCCR_START)
- chSchDoYieldS();
-#endif /* DMA2D_USE_WAIT */
-}
-
-/**
- * @brief Set background layer palette specifications.
- * @details Sets the palette specifications of the background layer.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] palettep pointer to the palette specifications
- *
- * @api
- */
-void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) {
-
- chSysLock();
- dma2dBgSetPaletteS(dma2dp, palettep);
- chSysUnlock();
-}
-
-/**
- * @brief Get background layer specifications.
- * @details Gets the background layer specifications at once.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(cfgp != NULL);
-
- cfgp->bufferp = dma2dBgGetAddressI(dma2dp);
- cfgp->wrap_offset = dma2dBgGetWrapOffsetI(dma2dp);
- cfgp->fmt = dma2dBgGetPixelFormatI(dma2dp);
- cfgp->def_color = dma2dBgGetDefaultColorI(dma2dp);
- cfgp->const_alpha = dma2dBgGetConstantAlphaI(dma2dp);
- if (cfgp->palettep != NULL)
- dma2dBgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep);
-}
-
-/**
- * @brief Get background layer specifications.
- * @details Gets the background layer specifications at once.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dBgGetLayerI(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/**
- * @brief Set background layer specifications.
- * @details Sets the background layer specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @sclass
- */
-void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(cfgp != NULL);
-
- dma2dBgSetAddressI(dma2dp, cfgp->bufferp);
- dma2dBgSetWrapOffsetI(dma2dp, cfgp->wrap_offset);
- dma2dBgSetPixelFormatI(dma2dp, cfgp->fmt);
- dma2dBgSetDefaultColorI(dma2dp, cfgp->def_color);
- dma2dBgSetConstantAlphaI(dma2dp, cfgp->const_alpha);
- if (cfgp->palettep != NULL)
- dma2dBgSetPaletteS(dma2dp, cfgp->palettep);
-}
-
-/**
- * @brief Set background layer specifications.
- * @details Sets the background layer specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dBgSetConfigS(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name DMA2D foreground layer methods
- * @{
- */
-
-/**
- * @brief Get foreground layer buffer address.
- * @details Gets the buffer address of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @iclass
- */
-void *dma2dFgGetAddressI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (void *)DMA2D->FGMAR;
-}
-
-/**
- * @brief Get foreground layer buffer address.
- * @details Gets the buffer address of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @api
- */
-void *dma2dFgGetAddress(DMA2DDriver *dma2dp) {
-
- void *bufferp;
- chSysLock();
- bufferp = dma2dFgGetAddressI(dma2dp);
- chSysUnlock();
- return bufferp;
-}
-
-/**
- * @brief Set foreground layer buffer address.
- * @details Sets the buffer address of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @iclass
- */
-void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(dma2dIsAligned(bufferp, dma2dFgGetPixelFormatI(dma2dp)));
- (void)dma2dp;
-
- DMA2D->FGMAR = (uint32_t)bufferp;
-}
-
-/**
- * @brief Set foreground layer buffer address.
- * @details Sets the buffer address of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @api
- */
-void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp) {
-
- chSysLock();
- dma2dFgSetAddressI(dma2dp, bufferp);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer wrap offset.
- * @details Gets the buffer line wrap offset of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @iclass
- */
-size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (size_t)(DMA2D->FGOR & DMA2D_FGOR_LO);
-}
-
-/**
- * @brief Get foreground layer wrap offset.
- * @details Gets the buffer line wrap offset of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @api
- */
-size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp) {
-
- size_t offset;
- chSysLock();
- offset = dma2dFgGetWrapOffsetI(dma2dp);
- chSysUnlock();
- return offset;
-}
-
-/**
- * @brief Set foreground layer wrap offset.
- * @details Sets the buffer line wrap offset of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @iclass
- */
-void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds");
- (void)dma2dp;
-
- DMA2D->FGOR = ((DMA2D->FGOR & ~DMA2D_FGOR_LO) |
- ((uint32_t)offset & DMA2D_FGOR_LO));
-}
-
-/**
- * @brief Set foreground layer wrap offset.
- * @details Sets the buffer line wrap offset of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @api
- */
-void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) {
-
- chSysLock();
- dma2dFgSetWrapOffsetI(dma2dp, offset);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer constant alpha.
- * @details Gets the constant alpha component of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return constant alpha component, A-8
- *
- * @iclass
- */
-uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (uint8_t)((DMA2D->FGPFCCR & DMA2D_FGPFCCR_ALPHA) >> 24);
-}
-
-/**
- * @brief Get foreground layer constant alpha.
- * @details Gets the constant alpha component of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return constant alpha component, A-8
- *
- * @api
- */
-uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp) {
-
- uint8_t a;
- chSysLock();
- a = dma2dFgGetConstantAlphaI(dma2dp);
- chSysUnlock();
- return a;
-}
-
-/**
- * @brief Set foreground layer constant alpha.
- * @details Sets the constant alpha component of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @iclass
- */
-void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_ALPHA) |
- (((uint32_t)a << 24) & DMA2D_FGPFCCR_ALPHA));
-}
-
-/**
- * @brief Set foreground layer constant alpha.
- * @details Sets the constant alpha component of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @api
- */
-void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) {
-
- chSysLock();
- dma2dFgSetConstantAlphaI(dma2dp, a);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer alpha mode.
- * @details Gets the alpha mode of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return alpha mode
- *
- * @iclass
- */
-dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_amode_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_AM);
-}
-
-/**
- * @brief Get foreground layer alpha mode.
- * @details Gets the alpha mode of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return alpha mode
- *
- * @api
- */
-dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp) {
-
- dma2d_amode_t mode;
- chSysLock();
- mode = dma2dFgGetAlphaModeI(dma2dp);
- chSysUnlock();
- return mode;
-}
-
-/**
- * @brief Set foreground layer alpha mode.
- * @details Sets the alpha mode of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode alpha mode
- *
- * @iclass
- */
-void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert((mode & ~DMA2D_FGPFCCR_AM) == 0, "bounds");
- osalDbgAssert((mode & DMA2D_FGPFCCR_AM) != DMA2D_FGPFCCR_AM, "bounds");
- (void)dma2dp;
-
- DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_AM) |
- ((uint32_t)mode & DMA2D_FGPFCCR_AM));
-}
-
-/**
- * @brief Set foreground layer alpha mode.
- * @details Sets the alpha mode of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] mode alpha mode
- *
- * @api
- */
-void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) {
-
- chSysLock();
- dma2dFgSetAlphaModeI(dma2dp, mode);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer pixel format.
- * @details Gets the pixel format of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @iclass
- */
-dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_pixfmt_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_CM);
-}
-
-/**
- * @brief Get foreground layer pixel format.
- * @details Gets the pixel format of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @api
- */
-dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp) {
-
- dma2d_pixfmt_t fmt;
- chSysLock();
- fmt = dma2dFgGetPixelFormatI(dma2dp);
- chSysUnlock();
- return fmt;
-}
-
-/**
- * @brief Set foreground layer pixel format.
- * @details Sets the pixel format of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @iclass
- */
-void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds");
- (void)dma2dp;
-
- DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_CM) |
- ((uint32_t)fmt & DMA2D_FGPFCCR_CM));
-}
-
-/**
- * @brief Set foreground layer pixel format.
- * @details Sets the pixel format of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @api
- */
-void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- chSysLock();
- dma2dFgSetPixelFormatI(dma2dp, fmt);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer default color.
- * @details Gets the default color of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, RGB-888
- *
- * @iclass
- */
-dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_color_t)(DMA2D->FGCOLR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get foreground layer default color.
- * @details Gets the default color of the foreground layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, RGB-888
- *
- * @api
- */
-dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp) {
-
- dma2d_color_t c;
- chSysLock();
- c = dma2dFgGetDefaultColorI(dma2dp);
- chSysUnlock();
- return c;
-}
-
-/**
- * @brief Set foreground layer default color.
- * @details Sets the default color of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, RGB-888
- *
- * @iclass
- */
-void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->FGCOLR = (uint32_t)c & 0x00FFFFFF;
-}
-
-/**
- * @brief Set foreground layer default color.
- * @details Sets the default color of the foreground layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, RGB-888
- *
- * @api
- */
-void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- chSysLock();
- dma2dFgSetDefaultColorI(dma2dp, c);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer palette specifications.
- * @details Gets the palette specifications of the foreground layer.
- * @note The palette colors pointer is actually addressed to a @p volatile
- * memory zone.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] palettep pointer to the palette specifications
- *
- * @iclass
- */
-void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) {
-
- uint32_t r;
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(palettep != NULL);
- (void)dma2dp;
-
- r = DMA2D->FGPFCCR;
- palettep->colorsp = (const void *)DMA2D->FGCLUT;
- palettep->length = (uint16_t)((r & DMA2D_FGPFCCR_CS) >> 8) + 1;
- palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_FGPFCCR_CCM) >> 4);
-}
-
-/**
- * @brief Get foreground layer palette specifications.
- * @details Gets the palette specifications of the foreground layer.
- * @note The palette colors pointer is actually addressed to a @p volatile
- * memory zone.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] palettep pointer to the palette specifications
- *
- * @api
- */
-void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) {
-
- chSysLock();
- dma2dFgGetPaletteI(dma2dp, palettep);
- chSysUnlock();
-}
-
-/**
- * @brief Set foreground layer palette specifications.
- * @details Sets the palette specifications of the foreground layer.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] palettep pointer to the palette specifications
- *
- * @sclass
- */
-void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(palettep != NULL);
- osalDbgCheck(palettep->colorsp != NULL);
- osalDbgAssert(palettep->length > 0, "bounds");
- osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds");
- osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) ||
- (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format");
-
- DMA2D->FGCMAR = (uint32_t)palettep->colorsp;
- DMA2D->FGPFCCR = (
- (DMA2D->FGPFCCR & ~(DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM)) |
- ((((uint32_t)palettep->length - 1) << 8) & DMA2D_FGPFCCR_CS) |
- ((uint32_t)palettep->fmt << 4)
- );
-
- dma2dp->state = DMA2D_ACTIVE;
- DMA2D->FGPFCCR |= DMA2D_FGPFCCR_START;
-
-#if DMA2D_USE_WAIT
- dma2dp->thread = chThdGetSelfX();
- chSchGoSleepS(CH_STATE_SUSPENDED);
-#else
- while (DMA2D->FGPFCCR & DMA2D_FGPFCCR_START)
- chSchDoYieldS();
-#endif /* DMA2D_USE_WAIT */
-}
-
-/**
- * @brief Set foreground layer palette specifications.
- * @details Sets the palette specifications of the foreground layer.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] palettep pointer to the palette specifications
- *
- * @api
- */
-void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) {
-
- chSysLock();
- dma2dFgSetPaletteS(dma2dp, palettep);
- chSysUnlock();
-}
-
-/**
- * @brief Get foreground layer specifications.
- * @details Gets the foreground layer specifications at once.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(cfgp != NULL);
-
- cfgp->bufferp = dma2dFgGetAddressI(dma2dp);
- cfgp->wrap_offset = dma2dFgGetWrapOffsetI(dma2dp);
- cfgp->fmt = dma2dFgGetPixelFormatI(dma2dp);
- cfgp->def_color = dma2dFgGetDefaultColorI(dma2dp);
- cfgp->const_alpha = dma2dFgGetConstantAlphaI(dma2dp);
- if (cfgp->palettep != NULL)
- dma2dFgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep);
-}
-
-/**
- * @brief Get foreground layer specifications.
- * @details Gets the foreground layer specifications at once.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dFgGetLayerI(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/**
- * @brief Set foreground layer specifications.
- * @details Sets the foreground layer specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @sclass
- */
-void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(cfgp != NULL);
-
- dma2dFgSetAddressI(dma2dp, cfgp->bufferp);
- dma2dFgSetWrapOffsetI(dma2dp, cfgp->wrap_offset);
- dma2dFgSetPixelFormatI(dma2dp, cfgp->fmt);
- dma2dFgSetDefaultColorI(dma2dp, cfgp->def_color);
- dma2dFgSetConstantAlphaI(dma2dp, cfgp->const_alpha);
- if (cfgp->palettep != NULL)
- dma2dFgSetPaletteS(dma2dp, cfgp->palettep);
-}
-
-/**
- * @brief Set foreground layer specifications.
- * @details Sets the foreground layer specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- * @note This function should not be called while the DMA2D is already
- * executing a job, otherwise the appropriate error interrupt might be
- * invoked.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dFgSetConfigS(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name DMA2D output layer methods
- * @{
- */
-
-/**
- * @brief Get output layer buffer address.
- * @details Gets the buffer address of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @iclass
- */
-void *dma2dOutGetAddressI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (void *)DMA2D->OMAR;
-}
-
-/**
- * @brief Get output layer buffer address.
- * @details Gets the buffer address of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return buffer address
- *
- * @api
- */
-void *dma2dOutGetAddress(DMA2DDriver *dma2dp) {
-
- void *bufferp;
- chSysLock();
- bufferp = dma2dOutGetAddressI(dma2dp);
- chSysUnlock();
- return bufferp;
-}
-
-/**
- * @brief Set output layer buffer address.
- * @details Sets the buffer address of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @iclass
- */
-void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(dma2dIsAligned(bufferp, dma2dOutGetPixelFormatI(dma2dp)));
- (void)dma2dp;
-
- DMA2D->OMAR = (uint32_t)bufferp;
-}
-
-/**
- * @brief Set output layer buffer address.
- * @details Sets the buffer address of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] bufferp buffer address
- *
- * @api
- */
-void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp) {
-
- chSysLock();
- dma2dOutSetAddressI(dma2dp, bufferp);
- chSysUnlock();
-}
-
-/**
- * @brief Get output layer wrap offset.
- * @details Gets the buffer line wrap offset of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @iclass
- */
-size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (size_t)(DMA2D->OOR & DMA2D_OOR_LO);
-}
-
-/**
- * @brief Get output layer wrap offset.
- * @details Gets the buffer line wrap offset of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return wrap offset, in pixels
- *
- * @api
- */
-size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp) {
-
- size_t offset;
- chSysLock();
- offset = dma2dOutGetWrapOffsetI(dma2dp);
- chSysUnlock();
- return offset;
-}
-
-/**
- * @brief Set output layer wrap offset.
- * @details Sets the buffer line wrap offset of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @iclass
- */
-void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds");
- (void)dma2dp;
-
- DMA2D->OOR = ((DMA2D->OOR & ~DMA2D_OOR_LO) |
- ((uint32_t)offset & DMA2D_OOR_LO));
-}
-
-/**
- * @brief Set output layer wrap offset.
- * @details Sets the buffer line wrap offset of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] offset wrap offset, in pixels
- *
- * @api
- */
-void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) {
-
- chSysLock();
- dma2dOutSetWrapOffsetI(dma2dp, offset);
- chSysUnlock();
-}
-
-/**
- * @brief Get output layer pixel format.
- * @details Gets the pixel format of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @iclass
- */
-dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_pixfmt_t)(DMA2D->OPFCCR & DMA2D_OPFCCR_CM);
-}
-
-/**
- * @brief Get output layer pixel format.
- * @details Gets the pixel format of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return pixel format
- *
- * @api
- */
-dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp) {
-
- dma2d_pixfmt_t fmt;
- chSysLock();
- fmt = dma2dOutGetPixelFormatI(dma2dp);
- chSysUnlock();
- return fmt;
-}
-
-/**
- * @brief Set output layer pixel format.
- * @details Sets the pixel format of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @iclass
- */
-void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgAssert(fmt <= DMA2D_MAX_OUTPIXFMT_ID, "bounds");
- (void)dma2dp;
-
- DMA2D->OPFCCR = ((DMA2D->OPFCCR & ~DMA2D_OPFCCR_CM) |
- ((uint32_t)fmt & DMA2D_OPFCCR_CM));
-}
-
-/**
- * @brief Set output layer pixel format.
- * @details Sets the pixel format of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] fmt pixel format
- *
- * @api
- */
-void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) {
-
- chSysLock();
- dma2dOutSetPixelFormatI(dma2dp, fmt);
- chSysUnlock();
-}
-
-/**
- * @brief Get output layer default color.
- * @details Gets the default color of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, chosen output format
- *
- * @iclass
- */
-dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- (void)dma2dp;
-
- return (dma2d_color_t)(DMA2D->OCOLR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get output layer default color.
- * @details Gets the default color of the output layer.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- *
- * @return default color, chosen output format
- *
- * @api
- */
-dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp) {
-
- dma2d_color_t c;
- chSysLock();
- c = dma2dOutGetDefaultColorI(dma2dp);
- chSysUnlock();
- return c;
-}
-
-/**
- * @brief Set output layer default color.
- * @details Sets the default color of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, chosen output format
- *
- * @iclass
- */
-void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- (void)dma2dp;
-
- DMA2D->OCOLR = (uint32_t)c & 0x00FFFFFF;
-}
-
-/**
- * @brief Set output layer default color.
- * @details Sets the default color of the output layer.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] c default color, chosen output format
- *
- * @api
- */
-void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) {
-
- chSysLock();
- dma2dOutSetDefaultColorI(dma2dp, c);
- chSysUnlock();
-}
-
-/**
- * @brief Get output layer specifications.
- * @details Gets the output layer specifications at once.
- * @note Constant alpha and palette specifications are ignored.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgCheck(cfgp != NULL);
-
- cfgp->bufferp = dma2dOutGetAddressI(dma2dp);
- cfgp->wrap_offset = dma2dOutGetWrapOffsetI(dma2dp);
- cfgp->fmt = dma2dOutGetPixelFormatI(dma2dp);
- cfgp->def_color = dma2dOutGetDefaultColorI(dma2dp);
-}
-
-/**
- * @brief Get output layer specifications.
- * @details Gets the output layer specifications at once.
- * @note Constant alpha and palette specifications are ignored.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dOutGetLayerI(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/**
- * @brief Set output layer specifications.
- * @details Sets the output layer specifications at once.
- * @note Constant alpha and palette specifications are ignored.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(dma2dp == &DMA2DD1);
- osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready");
- osalDbgCheck(cfgp != NULL);
-
- dma2dOutSetAddressI(dma2dp, cfgp->bufferp);
- dma2dOutSetWrapOffsetI(dma2dp, cfgp->wrap_offset);
- dma2dOutSetPixelFormatI(dma2dp, cfgp->fmt);
- dma2dOutSetDefaultColorI(dma2dp, cfgp->def_color);
-}
-
-/**
- * @brief Set output layer specifications.
- * @details Sets the output layer specifications at once.
- * @note Constant alpha and palette specifications are ignored.
- * @pre DMA2D is ready.
- *
- * @param[in] dma2dp pointer to the @p DMA2DDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @api
- */
-void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) {
-
- chSysLock();
- dma2dOutSetConfigI(dma2dp, cfgp);
- chSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name DMA2D helper functions
- * @{
- */
-
-/**
- * @brief Compute pixel address.
- * @details Computes the buffer address of a pixel, given the buffer
- * specifications.
- *
- * @param[in] originp buffer origin address
- * @param[in] pitch buffer pitch, in bytes
- * @param[in] fmt buffer pixel format
- * @param[in] x horizontal pixel coordinate
- * @param[in] y vertical pixel coordinate
- *
- * @return pixel address, constant data
- *
- * @api
- */
-const void *dma2dComputeAddressConst(const void *originp, size_t pitch,
- dma2d_pixfmt_t fmt,
- uint16_t x, uint16_t y) {
-
- osalDbgCheck(pitch > 0);
-
- switch (fmt) {
- case DMA2D_FMT_ARGB8888:
- return (const void *)((uintptr_t)originp +
- (uintptr_t)y * pitch + (uintptr_t)x * 4);
- case DMA2D_FMT_RGB888:
- return (const void *)((uintptr_t)originp +
- (uintptr_t)y * pitch + (uintptr_t)x * 3);
- case DMA2D_FMT_RGB565:
- case DMA2D_FMT_ARGB1555:
- case DMA2D_FMT_ARGB4444:
- case DMA2D_FMT_AL88:
- return (const void *)((uintptr_t)originp +
- (uintptr_t)y * pitch + (uintptr_t)x * 2);
- case DMA2D_FMT_L8:
- case DMA2D_FMT_AL44:
- case DMA2D_FMT_A8:
- return (const void *)((uintptr_t)originp +
- (uintptr_t)y * pitch + (uintptr_t)x);
- case DMA2D_FMT_L4:
- case DMA2D_FMT_A4:
- osalDbgAssert((x & 1) == 0, "not aligned");
- return (const void *)((uintptr_t)originp +
- (uintptr_t)y * pitch + (uintptr_t)x / 2);
- default:
- osalDbgAssert(false, "invalid format");
- return NULL;
- }
-}
-
-/**
- * @brief Address is aligned.
- * @details Tells whether the address is aligned with the provided pixel format.
- *
- * @param[in] bufferp address
- * @param[in] fmt pixel format
- *
- * @return address is aligned
- *
- * @api
- */
-bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt) {
-
- switch (fmt) {
- case DMA2D_FMT_ARGB8888:
- case DMA2D_FMT_RGB888:
- return ((uintptr_t)bufferp & 3) == 0; /* 32-bit alignment.*/
- case DMA2D_FMT_RGB565:
- case DMA2D_FMT_ARGB1555:
- case DMA2D_FMT_ARGB4444:
- case DMA2D_FMT_AL88:
- return ((uintptr_t)bufferp & 1) == 0; /* 16-bit alignment.*/
- case DMA2D_FMT_L8:
- case DMA2D_FMT_AL44:
- case DMA2D_FMT_L4:
- case DMA2D_FMT_A8:
- case DMA2D_FMT_A4:
- return true; /* 8-bit alignment.*/
- default:
- osalDbgAssert(false, "invalid format");
- return false;
- }
-}
-
-/**
- * @brief Compute bits per pixel.
- * @details Computes the bits per pixel for the specified pixel format.
- *
- * @param[in] fmt pixel format
- *
- * @retuen bits per pixel
- *
- * @api
- */
-size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt) {
-
- osalDbgAssert(fmt < DMA2D_MAX_PIXFMT_ID, "invalid format");
-
- return (size_t)dma2d_bpp[(unsigned)fmt];
-}
-
-#if DMA2D_USE_SOFTWARE_CONVERSIONS || defined(__DOXYGEN__)
-
-/**
- * @brief Convert from ARGB-8888.
- * @details Converts an ARGB-8888 color to the specified pixel format.
- *
- * @param[in] c color, ARGB-8888
- * @param[in] fmt target pixel format
- *
- * @return raw color value for the target pixel format, left
- * padded with zeros.
- *
- * @api
- */
-dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) {
-
- switch (fmt) {
- case DMA2D_FMT_ARGB8888: {
- return c;
- }
- case DMA2D_FMT_RGB888: {
- return (c & 0x00FFFFFF);
- }
- case DMA2D_FMT_RGB565: {
- return (((c & 0x000000F8) >> ( 8 - 5)) |
- ((c & 0x0000FC00) >> (16 - 11)) |
- ((c & 0x00F80000) >> (24 - 16)));
- }
- case DMA2D_FMT_ARGB1555: {
- return (((c & 0x000000F8) >> ( 8 - 5)) |
- ((c & 0x0000F800) >> (16 - 10)) |
- ((c & 0x00F80000) >> (24 - 15)) |
- ((c & 0x80000000) >> (32 - 16)));
- }
- case DMA2D_FMT_ARGB4444: {
- return (((c & 0x000000F0) >> ( 8 - 4)) |
- ((c & 0x0000F000) >> (16 - 8)) |
- ((c & 0x00F00000) >> (24 - 12)) |
- ((c & 0xF0000000) >> (32 - 16)));
- }
- case DMA2D_FMT_L8: {
- return (c & 0x000000FF);
- }
- case DMA2D_FMT_AL44: {
- return (((c & 0x000000F0) >> ( 8 - 4)) |
- ((c & 0xF0000000) >> (32 - 8)));
- }
- case DMA2D_FMT_AL88: {
- return (((c & 0x000000FF) >> ( 8 - 8)) |
- ((c & 0xFF000000) >> (32 - 16)));
- }
- case DMA2D_FMT_L4: {
- return (c & 0x0000000F);
- }
- case DMA2D_FMT_A8: {
- return ((c & 0xFF000000) >> (32 - 8));
- }
- case DMA2D_FMT_A4: {
- return ((c & 0xF0000000) >> (32 - 4));
- }
- default:
- osalDbgAssert(false, "invalid format");
- return 0;
- }
-}
-
-/**
- * @brief Convert to ARGB-8888.
- * @details Converts color of the specified pixel format to an ARGB-8888 color.
- *
- * @param[in] c color for the source pixel format, left padded with
- * zeros.
- * @param[in] fmt source pixel format
- *
- * @return color in ARGB-8888 format
- *
- * @api
- */
-dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) {
-
- switch (fmt) {
- case DMA2D_FMT_ARGB8888: {
- return c;
- }
- case DMA2D_FMT_RGB888: {
- return ((c & 0x00FFFFFF) | 0xFF000000);
- }
- case DMA2D_FMT_RGB565: {
- register dma2d_color_t output = 0xFF000000;
- if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007);
- if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300);
- if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000);
- return output;
- }
- case DMA2D_FMT_ARGB1555: {
- register dma2d_color_t output = 0x00000000;
- if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007);
- if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700);
- if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000);
- if (c & 0x8000) output |= 0xFF000000;
- return output;
- }
- case DMA2D_FMT_ARGB4444: {
- register dma2d_color_t output = 0x00000000;
- if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F);
- if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00);
- if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000);
- if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000);
- return output;
- }
- case DMA2D_FMT_L8: {
- return (c & 0xFF) | 0xFF000000;
- }
- case DMA2D_FMT_AL44: {
- register dma2d_color_t output = 0x00000000;
- if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F);
- if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000);
- return output;
- }
- case DMA2D_FMT_AL88: {
- return (((c & 0x00FF) << ( 8 - 8)) |
- ((c & 0xFF00) << (32 - 16)));
- }
- case DMA2D_FMT_L4: {
- return ((c & 0x0F) | 0xFF000000);
- }
- case DMA2D_FMT_A8: {
- return ((c & 0xFF) << (32 - 8));
- }
- case DMA2D_FMT_A4: {
- return ((c & 0x0F) << (32 - 4));
- }
- default:
- osalDbgAssert(false, "invalid format");
- return 0;
- }
-}
-
-#endif /* DMA2D_NEED_CONVERSIONS */
-
-/** @} */
-
-/** @} */
-
-#endif /* STM32_DMA2D_USE_DMA2D */
+/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_dma2d.c + * @brief DMA2D/Chrom-ART driver. + */ + +#include "ch.h" +#include "hal.h" + +#include "hal_stm32_dma2d.h" + +#if STM32_DMA2D_USE_DMA2D || defined(__DOXYGEN__) + +/* Ignore annoying warning messages for actually safe code.*/ +#if defined(__GNUC__) && !defined(__DOXYGEN__) +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * @addtogroup dma2d + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief DMA2DD1 driver identifier.*/ +DMA2DDriver DMA2DD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Bits per pixel lookup table. + */ +static const uint8_t dma2d_bpp[DMA2D_MAX_PIXFMT_ID + 1] = { + 32, /* DMA2D_FMT_ARGB8888 */ + 24, /* DMA2D_FMT_RGB888 */ + 16, /* DMA2D_FMT_RGB565 */ + 16, /* DMA2D_FMT_ARGB1555 */ + 16, /* DMA2D_FMT_ARGB4444 */ + 8, /* DMA2D_FMT_L8 */ + 8, /* DMA2D_FMT_AL44 */ + 16, /* DMA2D_FMT_AL88 */ + 4, /* DMA2D_FMT_L4 */ + 8, /* DMA2D_FMT_A8 */ + 4 /* DMA2D_FMT_A4 */ +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @name DMA2D interrupt handlers + * @{ + */ + +/** + * @brief DMA2D global interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_DMA2D_HANDLER) { + + DMA2DDriver *const dma2dp = &DMA2DD1; + bool job_done = false; + thread_t *tp = NULL; + + OSAL_IRQ_PROLOGUE(); + + /* Handle Configuration Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CEIF) && (DMA2D->CR & DMA2D_CR_CEIE)) { + if (dma2dp->config->cfgerr_isr != NULL) + dma2dp->config->cfgerr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCEIF; + } + + /* Handle CLUT (Palette) Transfer Complete ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CTCIF) && (DMA2D->CR & DMA2D_CR_CTCIE)) { + if (dma2dp->config->paltrfdone_isr != NULL) + dma2dp->config->paltrfdone_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCTCIF; + } + + /* Handle CLUT (Palette) Access Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_CAEIF) && (DMA2D->CR & DMA2D_CR_CAEIE)) { + if (dma2dp->config->palacserr_isr != NULL) + dma2dp->config->palacserr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CCAEIF; + } + + /* Handle Transfer Watermark ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TWIF) && (DMA2D->CR & DMA2D_CR_TWIE)) { + if (dma2dp->config->trfwmark_isr != NULL) + dma2dp->config->trfwmark_isr(dma2dp); + DMA2D->IFCR |= DMA2D_IFSR_CTWIF; + } + + /* Handle Transfer Complete ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TCIF) && (DMA2D->CR & DMA2D_CR_TCIE)) { + if (dma2dp->config->trfdone_isr != NULL) + dma2dp->config->trfdone_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CTCIF; + } + + /* Handle Transfer Error ISR.*/ + if ((DMA2D->ISR & DMA2D_ISR_TEIF) && (DMA2D->CR & DMA2D_CR_TEIE)) { + if (dma2dp->config->trferr_isr != NULL) + dma2dp->config->trferr_isr(dma2dp); + job_done = true; + DMA2D->IFCR |= DMA2D_IFSR_CTEIF; + } + + if (job_done) { + osalSysLockFromISR(); + osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); + + #if DMA2D_USE_WAIT + /* Wake the waiting thread up.*/ + if (dma2dp->thread != NULL) { + tp = dma2dp->thread; + dma2dp->thread = NULL; + tp->u.rdymsg = MSG_OK; + chSchReadyI(tp); + } + #endif /* DMA2D_USE_WAIT */ + + dma2dp->state = DMA2D_READY; + osalSysUnlockFromISR(); + } + + OSAL_IRQ_EPILOGUE(); +} + +/** @} */ + +/** + * @name DMA2D driver-specific methods + * @{ + */ + +/** + * @brief DMA2D Driver initialization. + * @details Initializes the DMA2D subsystem and chosen drivers. Should be + * called at board initialization. + * + * @init + */ +void dma2dInit(void) { + + /* Reset the DMA2D hardware module.*/ + rccResetDMA2D(); + + /* Enable the DMA2D clock.*/ + rccEnableDMA2D(false); + + /* Driver struct initialization.*/ + dma2dObjectInit(&DMA2DD1); + DMA2DD1.state = DMA2D_STOP; +} + +/** + * @brief Initializes the standard part of a @p DMA2DDriver structure. + * + * @param[out] dma2dp pointer to the @p DMA2DDriver object + * + * @init + */ +void dma2dObjectInit(DMA2DDriver *dma2dp) { + + osalDbgCheck(dma2dp == &DMA2DD1); + + dma2dp->state = DMA2D_UNINIT; + dma2dp->config = NULL; +#if DMA2D_USE_WAIT + dma2dp->thread = NULL; +#endif /* DMA2D_USE_WAIT */ +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxObjectInit(&dma2dp->lock); +#else + chSemObjectInit(&dma2dp->lock, 1); +#endif +#endif /* (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) */ +} + +/** + * @brief Get the driver state. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @retun driver state + * + * @iclass + */ +dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp) { + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheckClassI(); + + return dma2dp->state; +} + +/** + * @brief Get the driver state. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @retun driver state + * + * @api + */ +dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp) { + + dma2d_state_t state; + chSysLock(); + state = dma2dGetStateI(dma2dp); + chSysUnlock(); + return state; +} + +/** + * @brief Configures and activates the DMA2D peripheral. + * @pre DMA2D is stopped. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] configp pointer to the @p DMA2DConfig object + * + * @api + */ +void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp) { + + chSysLock(); + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(configp != NULL); + osalDbgAssert(dma2dp->state == DMA2D_STOP, "invalid state"); + + dma2dp->config = configp; + + /* Turn off the controller and its interrupts.*/ + DMA2D->CR = 0; + + /* Enable interrupts, except Line Watermark.*/ + nvicEnableVector(STM32_DMA2D_NUMBER, STM32_DMA2D_IRQ_PRIORITY); + + DMA2D->CR = (DMA2D_CR_CEIE | DMA2D_CR_CTCIE | DMA2D_CR_CAEIE | + DMA2D_CR_TCIE | DMA2D_CR_TEIE); + + dma2dp->state = DMA2D_READY; + chSysUnlock(); +} + +/** + * @brief Deactivates the DMA2D peripheral. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dStop(DMA2DDriver *dma2dp) { + + chSysLock(); + + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "invalid state"); +#if DMA2D_USE_WAIT + osalDbgAssert(dma2dp->thread == NULL, "still waiting"); +#endif /* DMA2D_USE_WAIT */ + + dma2dp->state = DMA2D_STOP; + chSysUnlock(); +} + +#if DMA2D_USE_MUTUAL_EXCLUSION + +/** + * @brief Gains exclusive access to the DMA2D module. + * @details This function tries to gain ownership to the DMA2D module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dAcquireBusS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxLockS(&dma2dp->lock); +#else + chSemWaitS(&dma2dp->lock); +#endif +} + +/** + * @brief Gains exclusive access to the DMA2D module. + * @details This function tries to gain ownership to the DMA2D module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dAcquireBus(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dAcquireBusS(dma2dp); + chSysUnlock(); +} + +/** + * @brief Releases exclusive access to the DMA2D module. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dReleaseBusS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxUnlockS(&dma2dp->lock); +#else + chSemSignalI(&dma2dp->lock); +#endif +} + +/** + * @brief Releases exclusive access to the DMA2D module. + * @pre In order to use this function the option + * @p DMA2D_USE_MUTUAL_EXCLUSION must be enabled. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dReleaseBus(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dReleaseBusS(dma2dp); + chSysUnlock(); +} + +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ + +/** @} */ + +/** + * @name DMA2D global methods + * @{ + */ + +/** + * @brief Get watermark position. + * @details Gets the watermark line position. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return watermark line position + * + * @iclass + */ +uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint16_t)(DMA2D->LWR & DMA2D_LWR_LW); +} + +/** + * @brief Get watermark position. + * @details Gets the watermark line position. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return watermark line position + * + * @api + */ +uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp) { + + uint16_t line; + chSysLock(); + line = dma2dGetWatermarkPosI(dma2dp); + chSysUnlock(); + return line; +} + +/** + * @brief Set watermark position. + * @details Sets the watermark line position. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] line watermark line position + * + * @iclass + */ +void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->LWR = ((DMA2D->LWR & ~DMA2D_LWR_LW) | + ((uint32_t)line & DMA2D_LWR_LW)); +} + +/** + * @brief Set watermark position. + * @details Sets the watermark line position. + * @note The interrupt is invoked after the last pixel of the watermark line + * is written. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] line watermark line position + * + * @iclass + */ +void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line) { + + chSysLock(); + dma2dSetWatermarkPosI(dma2dp, line); + chSysUnlock(); +} + +/** + * @brief Watermark interrupt enabled. + * @details Tells whether the watermark interrupt is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @iclass + */ +bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->CR & DMA2D_CR_TWIE) != 0; +} + +/** + * @brief Watermark interrupt enabled. + * @details Tells whether the watermark interrupt is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @api + */ +bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp) { + + bool enabled; + chSysLock(); + enabled = dma2dIsWatermarkEnabledI(dma2dp); + chSysUnlock(); + return enabled; +} + +/** + * @brief Enable watermark interrupt. + * @details Enables the watermark interrupt. The interrupt is invoked after the + * last pixel of the watermark line is written to the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dEnableWatermarkI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->CR |= DMA2D_CR_TWIE; +} + +/** + * @brief Enable watermark interrupt. + * @details Enables the watermark interrupt. The interrupt is invoked after the + * last pixel of the watermark line is written to the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dEnableWatermark(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dEnableWatermarkI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Disable watermark interrupt. + * @details Disables the watermark interrupt. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dDisableWatermarkI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->CR &= ~DMA2D_CR_TWIE; +} + +/** + * @brief Disable watermark interrupt. + * @details Disables the watermark interrupt. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dDisableWatermark(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dDisableWatermarkI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Get dead time cycles. + * @details Gets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return dead time, in DMA2D clock cycles + * + * @iclass + */ +uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->AMTCR & DMA2D_AMTCR_DT) >> 8; +} + +/** + * @brief Get dead time cycles. + * @details Gets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return dead time, in DMA2D clock cycles + * + * @api + */ +uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp) { + + uint32_t cycles; + chSysLock(); + cycles = dma2dGetDeadTimeI(dma2dp); + chSysUnlock(); + return cycles; +} + +/** + * @brief Set dead time cycles. + * @details Sets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cycles dead time, in DMA2D clock cycles + * + * @iclass + */ +void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(cycles <= DMA2D_MAX_DEADTIME_CYCLES, "bounds"); + (void)dma2dp; + + DMA2D->AMTCR = ((DMA2D->AMTCR & ~DMA2D_AMTCR_DT) | + ((cycles << 8) & DMA2D_AMTCR_DT)); +} + +/** + * @brief Set dead time cycles. + * @details Sets the minimum dead time DMA2D clock cycles between DMA2D + * transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cycles dead time, in DMA2D clock cycles + * + * @api + */ +void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles) { + + chSysLock(); + dma2dSetDeadTimeI(dma2dp, cycles); + chSysUnlock(); +} + +/** + * @brief Dead time enabled. + * @details Tells whether the dead time between DMA2D transactions is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @iclass + */ +bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (DMA2D->AMTCR & DMA2D_AMTCR_EN) != 0; +} + +/** + * @brief Dead time enabled. + * @details Tells whether the dead time between DMA2D transactions is enabled. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return enabled + * + * @api + */ +bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp) { + + bool enabled; + chSysLock(); + enabled = dma2dIsDeadTimeEnabledI(dma2dp); + chSysUnlock(); + return enabled; +} + +/** + * @brief Enable dead time. + * @details Enables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->AMTCR |= DMA2D_AMTCR_EN; +} + +/** + * @brief Enable dead time. + * @details Enables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dEnableDeadTime(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dEnableDeadTimeI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Disable dead time. + * @details Disables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + DMA2D->AMTCR &= ~DMA2D_AMTCR_EN; +} + +/** + * @brief Disable dead time. + * @details Disables the dead time between DMA2D transactions. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dDisableDeadTime(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dDisableDeadTimeI(dma2dp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D job (transaction) methods + * @{ + */ + +/** + * @brief Get job mode. + * @details Gets the job mode. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return job mode + * + * @iclass + */ +dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_jobmode_t)(DMA2D->CR & DMA2D_CR_MODE); +} + +/** + * @brief Get job mode. + * @details Gets the job mode. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return job mode + * + * @api + */ +dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp) { + + dma2d_jobmode_t mode; + chSysLock(); + mode = dma2dJobGetModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set job mode. + * @details Sets the job mode. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode job mode + * + * @iclass + */ +void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_CR_MODE) == 0, "bounds"); + (void)dma2dp; + + DMA2D->CR = ((DMA2D->CR & ~DMA2D_CR_MODE) | + ((uint32_t)mode & DMA2D_CR_MODE)); +} + +/** + * @brief Set job mode. + * @details Sets the job mode. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode job mode + * + * @api + */ +void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode) { + + chSysLock(); + dma2dJobSetModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get job size. + * @details Gets the job size. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] widthp pointer to the job width, in pixels + * @param[out] heightp pointer to the job height, in pixels + * + * @iclass + */ +void dma2dJobGetSizeI(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(widthp != NULL); + osalDbgCheck(heightp != NULL); + (void)dma2dp; + + r = DMA2D->NLR; + *widthp = (uint16_t)((r & DMA2D_NLR_PL) >> 16); + *heightp = (uint16_t)((r & DMA2D_NLR_NL) >> 0); +} + +/** + * @brief Get job size. + * @details Gets the job size. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] widthp pointer to the job width, in pixels + * @param[out] heightp pointer to the job height, in pixels + * + * @api + */ +void dma2dJobGetSize(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp) { + + chSysLock(); + dma2dJobGetSizeI(dma2dp, widthp, heightp); + chSysUnlock(); +} + +/** + * @brief Set job size. + * @details Sets the job size. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] widthp job width, in pixels + * @param[in] heightp job height, in pixels + * + * @iclass + */ +void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(width <= DMA2D_MAX_WIDTH, "bounds"); + osalDbgAssert(height <= DMA2D_MAX_HEIGHT, "bounds"); + (void)dma2dp; + + DMA2D->NLR = ((((uint32_t)width << 16) & DMA2D_NLR_PL) | + (((uint32_t)height << 0) & DMA2D_NLR_NL)); +} + +/** + * @brief Set job size. + * @details Sets the job size. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] widthp job width, in pixels + * @param[in] heightp job height, in pixels + * + * @api + */ +void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height) { + + chSysLock(); + dma2dJobSetSizeI(dma2dp, width, height); + chSysUnlock(); +} + +/** + * @brief Job executing. + * @details Tells whether a job (transaction) is active or paused. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return executing + * + * @iclass + */ +bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + + return dma2dp->state > DMA2D_READY; +} + +/** + * @brief Job executing. + * @details Tells whether a job (transaction) is active or paused. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return executing + * + * @api + */ +bool dma2dJobIsExecuting(DMA2DDriver *dma2dp) { + + bool executing; + chSysLock(); + executing = dma2dJobIsExecutingI(dma2dp); + chSysUnlock(); + return executing; +} + +/** + * @brief Start job. + * @details The job is started, and the DMA2D is set to active. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobStartI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->CR |= DMA2D_CR_START; +} + +/** + * @brief Start job. + * @details The job is started, and the DMA2D is set to active. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobStart(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobStartI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Execute job. + * @details Starts the job and waits for its completion, synchronously. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @sclass + */ +void dma2dJobExecuteS(DMA2DDriver *dma2dp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + + dma2dJobStartI(dma2dp); +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->CR & DMA2D_CR_START) + chSchDoYieldS(); +#endif +} + +/** + * @brief Execute job. + * @details Starts the job and waits for its completion, synchronously. + * @note Should there be invalid parameters, the appropriate interrupt + * handler will be invoked, and the DMA2D set back to ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobExecute(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobExecuteS(dma2dp); + chSysUnlock(); +} + +/** + * @brief Suspend current job. + * @details Suspends the current job. The driver is set to a paused state. + * @pre There is an active job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobSuspendI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); + osalDbgAssert(dma2dp->state == DMA2D_ACTIVE, "invalid state"); + + dma2dp->state = DMA2D_PAUSED; + DMA2D->CR |= DMA2D_CR_SUSP; +} + +/** + * @brief Suspend current job. + * @details Suspends the current job. The driver is set to a paused state. + * @pre There is an active job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobSuspend(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobSuspendI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Resume current job. + * @details Resumes the current job. + * @pre There is a paused job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobResumeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) != 0); + osalDbgAssert(dma2dp->state == DMA2D_PAUSED, "invalid state"); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->CR &= ~DMA2D_CR_SUSP; +} + +/** + * @brief Resume current job. + * @details Resumes the current job. + * @pre There is a paused job. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobResume(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobResumeI(dma2dp); + chSysUnlock(); +} + +/** + * @brief Abort current job. + * @details Abots the current job (if any), and the driver becomes ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @iclass + */ +void dma2dJobAbortI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck((DMA2D->CR & DMA2D_CR_SUSP) == 0); + osalDbgAssert(dma2dp->state >= DMA2D_READY, "invalid state"); + + dma2dp->state = DMA2D_READY; + DMA2D->CR |= DMA2D_CR_ABORT; +} + +/** + * @brief Abort current job. + * @details Abots the current job (if any), and the driver becomes ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @api + */ +void dma2dJobAbort(DMA2DDriver *dma2dp) { + + chSysLock(); + dma2dJobAbortI(dma2dp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D background layer methods + * @{ + */ + +/** + * @brief Get background layer buffer address. + * @details Gets the buffer address of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dBgGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->BGMAR; +} + +/** + * @brief Get background layer buffer address. + * @details Gets the buffer address of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dBgGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dBgGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set background layer buffer address. + * @details Sets the buffer address of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dBgGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->BGMAR = (uint32_t)bufferp; +} + +/** + * @brief Set background layer buffer address. + * @details Sets the buffer address of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dBgSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get background layer wrap offset. + * @details Gets the buffer line wrap offset of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->BGOR & DMA2D_BGOR_LO); +} + +/** + * @brief Get background layer wrap offset. + * @details Gets the buffer line wrap offset of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dBgGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set background layer wrap offset. + * @details Sets the buffer line wrap offset of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->BGOR = ((DMA2D->BGOR & ~DMA2D_BGOR_LO) | + ((uint32_t)offset & DMA2D_BGOR_LO)); +} + +/** + * @brief Set background layer wrap offset. + * @details Sets the buffer line wrap offset of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dBgSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint8_t)((DMA2D->BGPFCCR & DMA2D_BGPFCCR_ALPHA) >> 24); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp) { + + uint8_t a; + chSysLock(); + a = dma2dBgGetConstantAlphaI(dma2dp); + chSysUnlock(); + return a; +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_ALPHA) | + (((uint32_t)a << 24) & DMA2D_BGPFCCR_ALPHA)); +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { + + chSysLock(); + dma2dBgSetConstantAlphaI(dma2dp, a); + chSysUnlock(); +} + +/** + * @brief Get background layer alpha mode. + * @details Gets the alpha mode of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @iclass + */ +dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_amode_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_AM); +} + +/** + * @brief Get background layer alpha mode. + * @details Gets the alpha mode of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @api + */ +dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp) { + + dma2d_amode_t mode; + chSysLock(); + mode = dma2dBgGetAlphaModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set background layer alpha mode. + * @details Sets the alpha mode of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @iclass + */ +void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_BGPFCCR_AM) == 0, "bounds"); + osalDbgAssert((mode & DMA2D_BGPFCCR_AM) != DMA2D_BGPFCCR_AM, "bounds"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_AM) | + ((uint32_t)mode & DMA2D_BGPFCCR_AM)); +} + +/** + * @brief Set background layer alpha mode. + * @details Sets the alpha mode of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @api + */ +void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + chSysLock(); + dma2dBgSetAlphaModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->BGPFCCR & DMA2D_BGPFCCR_CM); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dBgGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->BGPFCCR = ((DMA2D->BGPFCCR & ~DMA2D_BGPFCCR_CM) | + ((uint32_t)fmt & DMA2D_BGPFCCR_CM)); +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dBgSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->BGCOLR & 0x00FFFFFF); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @api + */ +dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dBgGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->BGCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dBgSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get background layer palette specifications. + * @details Gets the palette specifications of the background layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @iclass + */ +void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(palettep != NULL); + (void)dma2dp; + + r = DMA2D->BGPFCCR; + palettep->colorsp = (const void *)DMA2D->BGCLUT; + palettep->length = (uint16_t)((r & DMA2D_BGPFCCR_CS) >> 8) + 1; + palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_BGPFCCR_CCM) >> 4); +} + +/** + * @brief Get background layer palette specifications. + * @details Gets the palette specifications of the background layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @api + */ +void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dBgGetPaletteI(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Set background layer palette specifications. + * @details Sets the palette specifications of the background layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @sclass + */ +void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(palettep != NULL); + osalDbgCheck(palettep->colorsp != NULL); + osalDbgAssert(palettep->length > 0, "bounds"); + osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || + (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); + + DMA2D->BGCMAR = (uint32_t)palettep->colorsp; + DMA2D->BGPFCCR = ( + (DMA2D->BGPFCCR & ~(DMA2D_BGPFCCR_CS | DMA2D_BGPFCCR_CCM)) | + ((((uint32_t)palettep->length - 1) << 8) & DMA2D_BGPFCCR_CS) | + ((uint32_t)palettep->fmt << 4) + ); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->BGPFCCR |= DMA2D_BGPFCCR_START; + +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->BGPFCCR & DMA2D_BGPFCCR_START) + chSchDoYieldS(); +#endif /* DMA2D_USE_WAIT */ +} + +/** + * @brief Set background layer palette specifications. + * @details Sets the palette specifications of the background layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @api + */ +void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dBgSetPaletteS(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dBgGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dBgGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dBgGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dBgGetDefaultColorI(dma2dp); + cfgp->const_alpha = dma2dBgGetConstantAlphaI(dma2dp); + if (cfgp->palettep != NULL) + dma2dBgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dBgGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @sclass + */ +void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dBgSetAddressI(dma2dp, cfgp->bufferp); + dma2dBgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dBgSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dBgSetDefaultColorI(dma2dp, cfgp->def_color); + dma2dBgSetConstantAlphaI(dma2dp, cfgp->const_alpha); + if (cfgp->palettep != NULL) + dma2dBgSetPaletteS(dma2dp, cfgp->palettep); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dBgSetConfigS(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D foreground layer methods + * @{ + */ + +/** + * @brief Get foreground layer buffer address. + * @details Gets the buffer address of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dFgGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->FGMAR; +} + +/** + * @brief Get foreground layer buffer address. + * @details Gets the buffer address of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dFgGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dFgGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set foreground layer buffer address. + * @details Sets the buffer address of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dFgGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->FGMAR = (uint32_t)bufferp; +} + +/** + * @brief Set foreground layer buffer address. + * @details Sets the buffer address of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dFgSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get foreground layer wrap offset. + * @details Gets the buffer line wrap offset of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->FGOR & DMA2D_FGOR_LO); +} + +/** + * @brief Get foreground layer wrap offset. + * @details Gets the buffer line wrap offset of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dFgGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set foreground layer wrap offset. + * @details Sets the buffer line wrap offset of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->FGOR = ((DMA2D->FGOR & ~DMA2D_FGOR_LO) | + ((uint32_t)offset & DMA2D_FGOR_LO)); +} + +/** + * @brief Set foreground layer wrap offset. + * @details Sets the buffer line wrap offset of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dFgSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (uint8_t)((DMA2D->FGPFCCR & DMA2D_FGPFCCR_ALPHA) >> 24); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp) { + + uint8_t a; + chSysLock(); + a = dma2dFgGetConstantAlphaI(dma2dp); + chSysUnlock(); + return a; +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_ALPHA) | + (((uint32_t)a << 24) & DMA2D_FGPFCCR_ALPHA)); +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a) { + + chSysLock(); + dma2dFgSetConstantAlphaI(dma2dp, a); + chSysUnlock(); +} + +/** + * @brief Get foreground layer alpha mode. + * @details Gets the alpha mode of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @iclass + */ +dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_amode_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_AM); +} + +/** + * @brief Get foreground layer alpha mode. + * @details Gets the alpha mode of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return alpha mode + * + * @api + */ +dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp) { + + dma2d_amode_t mode; + chSysLock(); + mode = dma2dFgGetAlphaModeI(dma2dp); + chSysUnlock(); + return mode; +} + +/** + * @brief Set foreground layer alpha mode. + * @details Sets the alpha mode of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @iclass + */ +void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert((mode & ~DMA2D_FGPFCCR_AM) == 0, "bounds"); + osalDbgAssert((mode & DMA2D_FGPFCCR_AM) != DMA2D_FGPFCCR_AM, "bounds"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_AM) | + ((uint32_t)mode & DMA2D_FGPFCCR_AM)); +} + +/** + * @brief Set foreground layer alpha mode. + * @details Sets the alpha mode of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] mode alpha mode + * + * @api + */ +void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode) { + + chSysLock(); + dma2dFgSetAlphaModeI(dma2dp, mode); + chSysUnlock(); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->FGPFCCR & DMA2D_FGPFCCR_CM); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dFgGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_PIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->FGPFCCR = ((DMA2D->FGPFCCR & ~DMA2D_FGPFCCR_CM) | + ((uint32_t)fmt & DMA2D_FGPFCCR_CM)); +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dFgSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->FGCOLR & 0x00FFFFFF); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, RGB-888 + * + * @api + */ +dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dFgGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->FGCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dFgSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get foreground layer palette specifications. + * @details Gets the palette specifications of the foreground layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @iclass + */ +void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + uint32_t r; + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(palettep != NULL); + (void)dma2dp; + + r = DMA2D->FGPFCCR; + palettep->colorsp = (const void *)DMA2D->FGCLUT; + palettep->length = (uint16_t)((r & DMA2D_FGPFCCR_CS) >> 8) + 1; + palettep->fmt = (dma2d_pixfmt_t)((r & DMA2D_FGPFCCR_CCM) >> 4); +} + +/** + * @brief Get foreground layer palette specifications. + * @details Gets the palette specifications of the foreground layer. + * @note The palette colors pointer is actually addressed to a @p volatile + * memory zone. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] palettep pointer to the palette specifications + * + * @api + */ +void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dFgGetPaletteI(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Set foreground layer palette specifications. + * @details Sets the palette specifications of the foreground layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @sclass + */ +void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(palettep != NULL); + osalDbgCheck(palettep->colorsp != NULL); + osalDbgAssert(palettep->length > 0, "bounds"); + osalDbgAssert(palettep->length <= DMA2D_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(((palettep->fmt == DMA2D_FMT_ARGB8888) || + (palettep->fmt == DMA2D_FMT_RGB888)), "invalid format"); + + DMA2D->FGCMAR = (uint32_t)palettep->colorsp; + DMA2D->FGPFCCR = ( + (DMA2D->FGPFCCR & ~(DMA2D_FGPFCCR_CS | DMA2D_FGPFCCR_CCM)) | + ((((uint32_t)palettep->length - 1) << 8) & DMA2D_FGPFCCR_CS) | + ((uint32_t)palettep->fmt << 4) + ); + + dma2dp->state = DMA2D_ACTIVE; + DMA2D->FGPFCCR |= DMA2D_FGPFCCR_START; + +#if DMA2D_USE_WAIT + dma2dp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); +#else + while (DMA2D->FGPFCCR & DMA2D_FGPFCCR_START) + chSchDoYieldS(); +#endif /* DMA2D_USE_WAIT */ +} + +/** + * @brief Set foreground layer palette specifications. + * @details Sets the palette specifications of the foreground layer. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] palettep pointer to the palette specifications + * + * @api + */ +void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep) { + + chSysLock(); + dma2dFgSetPaletteS(dma2dp, palettep); + chSysUnlock(); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dFgGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dFgGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dFgGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dFgGetDefaultColorI(dma2dp); + cfgp->const_alpha = dma2dFgGetConstantAlphaI(dma2dp); + if (cfgp->palettep != NULL) + dma2dFgGetPaletteI(dma2dp, (dma2d_palcfg_t *)cfgp->palettep); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer specifications at once. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dFgGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @sclass + */ +void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassS(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dFgSetAddressI(dma2dp, cfgp->bufferp); + dma2dFgSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dFgSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dFgSetDefaultColorI(dma2dp, cfgp->def_color); + dma2dFgSetConstantAlphaI(dma2dp, cfgp->const_alpha); + if (cfgp->palettep != NULL) + dma2dFgSetPaletteS(dma2dp, cfgp->palettep); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * @note This function should not be called while the DMA2D is already + * executing a job, otherwise the appropriate error interrupt might be + * invoked. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dFgSetConfigS(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D output layer methods + * @{ + */ + +/** + * @brief Get output layer buffer address. + * @details Gets the buffer address of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @iclass + */ +void *dma2dOutGetAddressI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (void *)DMA2D->OMAR; +} + +/** + * @brief Get output layer buffer address. + * @details Gets the buffer address of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return buffer address + * + * @api + */ +void *dma2dOutGetAddress(DMA2DDriver *dma2dp) { + + void *bufferp; + chSysLock(); + bufferp = dma2dOutGetAddressI(dma2dp); + chSysUnlock(); + return bufferp; +} + +/** + * @brief Set output layer buffer address. + * @details Sets the buffer address of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @iclass + */ +void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(dma2dIsAligned(bufferp, dma2dOutGetPixelFormatI(dma2dp))); + (void)dma2dp; + + DMA2D->OMAR = (uint32_t)bufferp; +} + +/** + * @brief Set output layer buffer address. + * @details Sets the buffer address of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] bufferp buffer address + * + * @api + */ +void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp) { + + chSysLock(); + dma2dOutSetAddressI(dma2dp, bufferp); + chSysUnlock(); +} + +/** + * @brief Get output layer wrap offset. + * @details Gets the buffer line wrap offset of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @iclass + */ +size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (size_t)(DMA2D->OOR & DMA2D_OOR_LO); +} + +/** + * @brief Get output layer wrap offset. + * @details Gets the buffer line wrap offset of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return wrap offset, in pixels + * + * @api + */ +size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp) { + + size_t offset; + chSysLock(); + offset = dma2dOutGetWrapOffsetI(dma2dp); + chSysUnlock(); + return offset; +} + +/** + * @brief Set output layer wrap offset. + * @details Sets the buffer line wrap offset of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @iclass + */ +void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(offset <= DMA2D_MAX_OFFSET, "bounds"); + (void)dma2dp; + + DMA2D->OOR = ((DMA2D->OOR & ~DMA2D_OOR_LO) | + ((uint32_t)offset & DMA2D_OOR_LO)); +} + +/** + * @brief Set output layer wrap offset. + * @details Sets the buffer line wrap offset of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] offset wrap offset, in pixels + * + * @api + */ +void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset) { + + chSysLock(); + dma2dOutSetWrapOffsetI(dma2dp, offset); + chSysUnlock(); +} + +/** + * @brief Get output layer pixel format. + * @details Gets the pixel format of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @iclass + */ +dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_pixfmt_t)(DMA2D->OPFCCR & DMA2D_OPFCCR_CM); +} + +/** + * @brief Get output layer pixel format. + * @details Gets the pixel format of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return pixel format + * + * @api + */ +dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp) { + + dma2d_pixfmt_t fmt; + chSysLock(); + fmt = dma2dOutGetPixelFormatI(dma2dp); + chSysUnlock(); + return fmt; +} + +/** + * @brief Set output layer pixel format. + * @details Sets the pixel format of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgAssert(fmt <= DMA2D_MAX_OUTPIXFMT_ID, "bounds"); + (void)dma2dp; + + DMA2D->OPFCCR = ((DMA2D->OPFCCR & ~DMA2D_OPFCCR_CM) | + ((uint32_t)fmt & DMA2D_OPFCCR_CM)); +} + +/** + * @brief Set output layer pixel format. + * @details Sets the pixel format of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] fmt pixel format + * + * @api + */ +void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt) { + + chSysLock(); + dma2dOutSetPixelFormatI(dma2dp, fmt); + chSysUnlock(); +} + +/** + * @brief Get output layer default color. + * @details Gets the default color of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, chosen output format + * + * @iclass + */ +dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + (void)dma2dp; + + return (dma2d_color_t)(DMA2D->OCOLR & 0x00FFFFFF); +} + +/** + * @brief Get output layer default color. + * @details Gets the default color of the output layer. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * + * @return default color, chosen output format + * + * @api + */ +dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp) { + + dma2d_color_t c; + chSysLock(); + c = dma2dOutGetDefaultColorI(dma2dp); + chSysUnlock(); + return c; +} + +/** + * @brief Set output layer default color. + * @details Sets the default color of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, chosen output format + * + * @iclass + */ +void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + (void)dma2dp; + + DMA2D->OCOLR = (uint32_t)c & 0x00FFFFFF; +} + +/** + * @brief Set output layer default color. + * @details Sets the default color of the output layer. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] c default color, chosen output format + * + * @api + */ +void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c) { + + chSysLock(); + dma2dOutSetDefaultColorI(dma2dp, c); + chSysUnlock(); +} + +/** + * @brief Get output layer specifications. + * @details Gets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgCheck(cfgp != NULL); + + cfgp->bufferp = dma2dOutGetAddressI(dma2dp); + cfgp->wrap_offset = dma2dOutGetWrapOffsetI(dma2dp); + cfgp->fmt = dma2dOutGetPixelFormatI(dma2dp); + cfgp->def_color = dma2dOutGetDefaultColorI(dma2dp); +} + +/** + * @brief Get output layer specifications. + * @details Gets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dOutGetLayerI(dma2dp, cfgp); + chSysUnlock(); +} + +/** + * @brief Set output layer specifications. + * @details Sets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(dma2dp == &DMA2DD1); + osalDbgAssert(dma2dp->state == DMA2D_READY, "not ready"); + osalDbgCheck(cfgp != NULL); + + dma2dOutSetAddressI(dma2dp, cfgp->bufferp); + dma2dOutSetWrapOffsetI(dma2dp, cfgp->wrap_offset); + dma2dOutSetPixelFormatI(dma2dp, cfgp->fmt); + dma2dOutSetDefaultColorI(dma2dp, cfgp->def_color); +} + +/** + * @brief Set output layer specifications. + * @details Sets the output layer specifications at once. + * @note Constant alpha and palette specifications are ignored. + * @pre DMA2D is ready. + * + * @param[in] dma2dp pointer to the @p DMA2DDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp) { + + chSysLock(); + dma2dOutSetConfigI(dma2dp, cfgp); + chSysUnlock(); +} + +/** @} */ + +/** + * @name DMA2D helper functions + * @{ + */ + +/** + * @brief Compute pixel address. + * @details Computes the buffer address of a pixel, given the buffer + * specifications. + * + * @param[in] originp buffer origin address + * @param[in] pitch buffer pitch, in bytes + * @param[in] fmt buffer pixel format + * @param[in] x horizontal pixel coordinate + * @param[in] y vertical pixel coordinate + * + * @return pixel address, constant data + * + * @api + */ +const void *dma2dComputeAddressConst(const void *originp, size_t pitch, + dma2d_pixfmt_t fmt, + uint16_t x, uint16_t y) { + + osalDbgCheck(pitch > 0); + + switch (fmt) { + case DMA2D_FMT_ARGB8888: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 4); + case DMA2D_FMT_RGB888: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 3); + case DMA2D_FMT_RGB565: + case DMA2D_FMT_ARGB1555: + case DMA2D_FMT_ARGB4444: + case DMA2D_FMT_AL88: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x * 2); + case DMA2D_FMT_L8: + case DMA2D_FMT_AL44: + case DMA2D_FMT_A8: + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x); + case DMA2D_FMT_L4: + case DMA2D_FMT_A4: + osalDbgAssert((x & 1) == 0, "not aligned"); + return (const void *)((uintptr_t)originp + + (uintptr_t)y * pitch + (uintptr_t)x / 2); + default: + osalDbgAssert(false, "invalid format"); + return NULL; + } +} + +/** + * @brief Address is aligned. + * @details Tells whether the address is aligned with the provided pixel format. + * + * @param[in] bufferp address + * @param[in] fmt pixel format + * + * @return address is aligned + * + * @api + */ +bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: + case DMA2D_FMT_RGB888: + return ((uintptr_t)bufferp & 3) == 0; /* 32-bit alignment.*/ + case DMA2D_FMT_RGB565: + case DMA2D_FMT_ARGB1555: + case DMA2D_FMT_ARGB4444: + case DMA2D_FMT_AL88: + return ((uintptr_t)bufferp & 1) == 0; /* 16-bit alignment.*/ + case DMA2D_FMT_L8: + case DMA2D_FMT_AL44: + case DMA2D_FMT_L4: + case DMA2D_FMT_A8: + case DMA2D_FMT_A4: + return true; /* 8-bit alignment.*/ + default: + osalDbgAssert(false, "invalid format"); + return false; + } +} + +/** + * @brief Compute bits per pixel. + * @details Computes the bits per pixel for the specified pixel format. + * + * @param[in] fmt pixel format + * + * @retuen bits per pixel + * + * @api + */ +size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt) { + + osalDbgAssert(fmt < DMA2D_MAX_PIXFMT_ID, "invalid format"); + + return (size_t)dma2d_bpp[(unsigned)fmt]; +} + +#if DMA2D_USE_SOFTWARE_CONVERSIONS || defined(__DOXYGEN__) + +/** + * @brief Convert from ARGB-8888. + * @details Converts an ARGB-8888 color to the specified pixel format. + * + * @param[in] c color, ARGB-8888 + * @param[in] fmt target pixel format + * + * @return raw color value for the target pixel format, left + * padded with zeros. + * + * @api + */ +dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: { + return c; + } + case DMA2D_FMT_RGB888: { + return (c & 0x00FFFFFF); + } + case DMA2D_FMT_RGB565: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000FC00) >> (16 - 11)) | + ((c & 0x00F80000) >> (24 - 16))); + } + case DMA2D_FMT_ARGB1555: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000F800) >> (16 - 10)) | + ((c & 0x00F80000) >> (24 - 15)) | + ((c & 0x80000000) >> (32 - 16))); + } + case DMA2D_FMT_ARGB4444: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0x0000F000) >> (16 - 8)) | + ((c & 0x00F00000) >> (24 - 12)) | + ((c & 0xF0000000) >> (32 - 16))); + } + case DMA2D_FMT_L8: { + return (c & 0x000000FF); + } + case DMA2D_FMT_AL44: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0xF0000000) >> (32 - 8))); + } + case DMA2D_FMT_AL88: { + return (((c & 0x000000FF) >> ( 8 - 8)) | + ((c & 0xFF000000) >> (32 - 16))); + } + case DMA2D_FMT_L4: { + return (c & 0x0000000F); + } + case DMA2D_FMT_A8: { + return ((c & 0xFF000000) >> (32 - 8)); + } + case DMA2D_FMT_A4: { + return ((c & 0xF0000000) >> (32 - 4)); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +/** + * @brief Convert to ARGB-8888. + * @details Converts color of the specified pixel format to an ARGB-8888 color. + * + * @param[in] c color for the source pixel format, left padded with + * zeros. + * @param[in] fmt source pixel format + * + * @return color in ARGB-8888 format + * + * @api + */ +dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt) { + + switch (fmt) { + case DMA2D_FMT_ARGB8888: { + return c; + } + case DMA2D_FMT_RGB888: { + return ((c & 0x00FFFFFF) | 0xFF000000); + } + case DMA2D_FMT_RGB565: { + register dma2d_color_t output = 0xFF000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); + if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); + return output; + } + case DMA2D_FMT_ARGB1555: { + register dma2d_color_t output = 0x00000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); + if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); + if (c & 0x8000) output |= 0xFF000000; + return output; + } + case DMA2D_FMT_ARGB4444: { + register dma2d_color_t output = 0x00000000; + if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); + if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); + if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); + if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); + return output; + } + case DMA2D_FMT_L8: { + return (c & 0xFF) | 0xFF000000; + } + case DMA2D_FMT_AL44: { + register dma2d_color_t output = 0x00000000; + if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); + if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); + return output; + } + case DMA2D_FMT_AL88: { + return (((c & 0x00FF) << ( 8 - 8)) | + ((c & 0xFF00) << (32 - 16))); + } + case DMA2D_FMT_L4: { + return ((c & 0x0F) | 0xFF000000); + } + case DMA2D_FMT_A8: { + return ((c & 0xFF) << (32 - 8)); + } + case DMA2D_FMT_A4: { + return ((c & 0x0F) << (32 - 4)); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +#endif /* DMA2D_NEED_CONVERSIONS */ + +/** @} */ + +/** @} */ + +#endif /* STM32_DMA2D_USE_DMA2D */ diff --git a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h index 29efa71..01f0941 100644 --- a/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.h +++ b/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.h @@ -1,664 +1,664 @@ -/*
- Copyright (C) 2013-2015 Andrea Zoppi
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file stm32_dma2d.h
- * @brief DMA2D/Chrom-ART driver.
- *
- * @addtogroup dma2d
- * @{
- */
-
-#ifndef _STM32_DMA2D_H_
-#define _STM32_DMA2D_H_
-
-/**
- * @brief Using the DMA2D driver.
- */
-#if !defined(STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__)
-#define STM32_DMA2D_USE_DMA2D (FALSE)
-#endif
-
-#if (TRUE == STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @name DMA2D job modes
- * @{
- */
-#define DMA2D_JOB_COPY (0 << 16) /**< Copy, replace(FG only).*/
-#define DMA2D_JOB_CONVERT (1 << 16) /**< Copy, convert (FG + PFC).*/
-#define DMA2D_JOB_BLEND (2 << 16) /**< Copy, blend (FG + BG + PFC).*/
-#define DMA2D_JOB_CONST (3 << 16) /**< Default color only (FG REG).*/
-/** @} */
-
-/**
- * @name DMA2D enable flag
- * @{
- */
-#define DMA2D_EF_ENABLE (1 << 0) /**< DMA2D enabled.*/
-#define DMA2D_EF_DITHER (1 << 16) /**< Dithering enabled.*/
-#define DMA2D_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/
-#define DMA2D_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/
-#define DMA2D_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/
-#define DMA2D_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/
-
-/** Enable flags mask. */
-#define DMA2D_EF_MASK \
- (DMA2D_EF_ENABLE | DMA2D_EF_DITHER | DMA2D_EF_PIXCLK_INVERT | \
- DMA2D_EF_DATAEN_HIGH | DMA2D_EF_VSYNC_HIGH | DMA2D_EF_HSYNC_HIGH)
-/** @} */
-
-/**
- * @name DMA2D layer enable flags
- * @{
- */
-#define DMA2D_LEF_ENABLE (1 << 0) /**< Layer enabled*/
-#define DMA2D_LEF_KEYING (1 << 1) /**< Color keying enabled.*/
-#define DMA2D_LEF_PALETTE (1 << 4) /**< Palette enabled.*/
-
-/** Layer enable flag masks. */
-#define DMA2D_LEF_MASK \
- (DMA2D_LEF_ENABLE | DMA2D_LEF_KEYING | DMA2D_LEF_PALETTE)
-/** @} */
-
-/**
- * @name DMA2D pixel formats
- * @{
- */
-#define DMA2D_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/
-#define DMA2D_FMT_RGB888 (1) /**< RGB-888 format.*/
-#define DMA2D_FMT_RGB565 (2) /**< RGB-565 format.*/
-#define DMA2D_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/
-#define DMA2D_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/
-#define DMA2D_FMT_L8 (5) /**< L-8 format.*/
-#define DMA2D_FMT_AL44 (6) /**< AL-44 format.*/
-#define DMA2D_FMT_AL88 (7) /**< AL-88 format.*/
-#define DMA2D_FMT_L4 (8) /**< L-4 format.*/
-#define DMA2D_FMT_A8 (9) /**< A-8 format.*/
-#define DMA2D_FMT_A4 (10) /**< A-4 format.*/
-/** @} */
-
-/**
- * @name DMA2D pixel format aliased raw masks
- * @{
- */
-#define DMA2D_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/
-#define DMA2D_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/
-#define DMA2D_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/
-#define DMA2D_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/
-#define DMA2D_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/
-#define DMA2D_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/
-#define DMA2D_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/
-#define DMA2D_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/
-#define DMA2D_XMASK_L4 (0x0000000F) /**< L-4 aliased mask.*/
-#define DMA2D_XMASK_A8 (0xFF000000) /**< A-8 aliased mask.*/
-#define DMA2D_XMASK_A4 (0xF0000000) /**< A-4 aliased mask.*/
-/** @} */
-
-/**
- * @name DMA2D alpha modes
- * @{
- */
-#define DMA2D_ALPHA_KEEP (0x00000000) /**< Original alpha channel.*/
-#define DMA2D_ALPHA_REPLACE (0x00010000) /**< Replace with constant.*/
-#define DMA2D_ALPHA_MODULATE (0x00020000) /**< Modulate with constant.*/
-/** @} */
-
-/**
- * @name DMA2D parameter bounds
- * @{
- */
-
-#define DMA2D_MIN_PIXFMT_ID (0) /**< Minimum pixel format ID.*/
-#define DMA2D_MAX_PIXFMT_ID (11) /**< Maximum pixel format ID.*/
-#define DMA2D_MIN_OUTPIXFMT_ID (0) /**< Minimum output pixel format ID.*/
-#define DMA2D_MAX_OUTPIXFMT_ID (4) /**< Maximum output pixel format ID.*/
-
-#define DMA2D_MAX_OFFSET ((1 << 14) - 1)
-
-#define DMA2D_MAX_PALETTE_LENGTH (256) /***/
-
-#define DMA2D_MAX_WIDTH ((1 << 14) - 1)
-#define DMA2D_MAX_HEIGHT ((1 << 16) - 1)
-
-#define DMA2D_MAX_WATERMARK_POS ((1 << 16) - 1)
-
-#define DMA2D_MAX_DEADTIME_CYCLES ((1 << 8) - 1)
-
-/** @} */
-
-/**
- * @name DMA2D basic ARGB-8888 colors.
- * @{
- */
-/* Microsoft Windows default 16-color palette.*/
-#define DMA2D_COLOR_BLACK (0xFF000000)
-#define DMA2D_COLOR_MAROON (0xFF800000)
-#define DMA2D_COLOR_GREEN (0xFF008000)
-#define DMA2D_COLOR_OLIVE (0xFF808000)
-#define DMA2D_COLOR_NAVY (0xFF000080)
-#define DMA2D_COLOR_PURPLE (0xFF800080)
-#define DMA2D_COLOR_TEAL (0xFF008080)
-#define DMA2D_COLOR_SILVER (0xFFC0C0C0)
-#define DMA2D_COLOR_GRAY (0xFF808080)
-#define DMA2D_COLOR_RED (0xFFFF0000)
-#define DMA2D_COLOR_LIME (0xFF00FF00)
-#define DMA2D_COLOR_YELLOW (0xFFFFFF00)
-#define DMA2D_COLOR_BLUE (0xFF0000FF)
-#define DMA2D_COLOR_FUCHSIA (0xFFFF00FF)
-#define DMA2D_COLOR_AQUA (0xFF00FFFF)
-#define DMA2D_COLOR_WHITE (0xFFFFFFFF)
-/** @} */
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/**
- * @name DMA2D configuration options
- * @{
- */
-
-/**
- * @brief DMA2D event interrupt priority level setting.
- */
-#if !defined(STM32_DMA2D_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_DMA2D_IRQ_PRIORITY (11)
-#endif
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(DMA2D_USE_WAIT) || defined(__DOXYGEN__)
-#define DMA2D_USE_WAIT (TRUE)
-#endif
-
-/**
- * @brief Enables the @p dma2dAcquireBus() and @p dma2dReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(DMA2D_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define DMA2D_USE_MUTUAL_EXCLUSION (TRUE)
-#endif
-
-/**
- * @brief Provides software color conversion functions.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__)
-#define DMA2D_USE_SOFTWARE_CONVERSIONS (TRUE)
-#endif
-
-/**
- * @brief Enables checks for DMA2D functions.
- * @note Disabling this option saves both code and data space.
- * @note Disabling checks by ChibiOS will automatically disable DMA2D checks.
- */
-#if !defined(DMA2D_USE_CHECKS) || defined(__DOXYGEN__)
-#define DMA2D_USE_CHECKS (TRUE)
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-#if (TRUE != STM32_HAS_DMA2D)
-#error "DMA2D must be present when using the DMA2D subsystem"
-#endif
-
-#if (TRUE != STM32_DMA2D_USE_DMA2D) && (TRUE != STM32_HAS_DMA2D)
-#error "DMA2D not present in the selected device"
-#endif
-
-#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION)
-#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES)
-#error "DMA2D_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
-#endif
-#endif
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/* Complex types forwarding.*/
-typedef union dma2d_coloralias_t dma2d_coloralias_t;
-typedef struct dma2d_palcfg_t dma2d_palcfg_t;
-typedef struct dma2d_laycfg_t dma2d_layercfg_t;
-typedef struct DMA2DConfig DMA2DConfig;
-typedef enum dma2d_state_t dma2d_state_t;
-typedef struct DMA2DDriver DMA2DDriver;
-
-/**
- * @name DMA2D Data types
- * @{
- */
-
-/**
- * @brief DMA2D generic color.
- */
-typedef uint32_t dma2d_color_t;
-
-/**
- * @brief DMA2D color aliases.
- * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B).
- * Padding fields are prefixed with <tt>'x'</tt>, and should be clear
- * (all 0) before compression and set (all 1) after expansion.
- */
-typedef union dma2d_coloralias_t {
- struct {
- unsigned b : 8;
- unsigned g : 8;
- unsigned r : 8;
- unsigned a : 8;
- } argb8888; /**< Mapped ARGB-8888 bits.*/
- struct {
- unsigned b : 8;
- unsigned g : 8;
- unsigned r : 8;
- unsigned xa : 8;
- } rgb888; /**< Mapped RGB-888 bits.*/
- struct {
- unsigned xb : 3;
- unsigned b : 5;
- unsigned xg : 2;
- unsigned g : 6;
- unsigned xr : 3;
- unsigned r : 5;
- unsigned xa : 8;
- } rgb565; /**< Mapped RGB-565 bits.*/
- struct {
- unsigned xb : 3;
- unsigned b : 5;
- unsigned xg : 3;
- unsigned g : 5;
- unsigned xr : 3;
- unsigned r : 5;
- unsigned xa : 7;
- unsigned a : 1;
- } argb1555; /**< Mapped ARGB-1555 values.*/
- struct {
- unsigned xb : 4;
- unsigned b : 4;
- unsigned xg : 4;
- unsigned g : 4;
- unsigned xr : 4;
- unsigned r : 4;
- unsigned xa : 4;
- unsigned a : 4;
- } argb4444; /**< Mapped ARGB-4444 values.*/
- struct {
- unsigned l : 8;
- unsigned x : 16;
- unsigned xa : 8;
- } l8; /**< Mapped L-8 bits.*/
- struct {
- unsigned xl : 4;
- unsigned l : 4;
- unsigned x : 16;
- unsigned xa : 4;
- unsigned a : 4;
- } al44; /**< Mapped AL-44 bits.*/
- struct {
- unsigned l : 8;
- unsigned x : 16;
- unsigned a : 8;
- } al88; /**< Mapped AL-88 bits.*/
- struct {
- unsigned l : 4;
- unsigned xl : 4;
- unsigned x : 16;
- unsigned xa : 8;
- } l4; /**< Mapped L-4 bits.*/
- struct {
- unsigned x : 24;
- unsigned a : 8;
- } a8; /**< Mapped A-8 bits.*/
- struct {
- unsigned x : 24;
- unsigned xa : 4;
- unsigned a : 4;
- } a4; /**< Mapped A-4 bits.*/
- dma2d_color_t aliased; /**< Aliased raw bits.*/
-} dma2d_coloralias_t;
-
-/**
- * @brief DMA2D job (transfer) mode.
- */
-typedef uint32_t dma2d_jobmode_t;
-
-/**
- * @brief DMA2D pixel format.
- */
-typedef uint32_t dma2d_pixfmt_t;
-
-/**
- * @brief DMA2D alpha mode.
- */
-typedef uint32_t dma2d_amode_t;
-
-/**
- * @brief DMA2D ISR callback.
- */
-typedef void (*dma2d_isrcb_t)(DMA2DDriver *dma2dp);
-
-/**
- * @brief DMA2D palette specifications.
- */
-typedef struct dma2d_palcfg_t {
- const void *colorsp; /**< Pointer to color entries.*/
- uint16_t length; /**< Number of color entries.*/
- dma2d_pixfmt_t fmt; /**< Format, RGB-888 or ARGB-8888.*/
-} dma2d_palcfg_t;
-
-/**
- * @brief DMA2D layer specifications.
- */
-typedef struct dma2d_layercfg_t {
- void *bufferp; /**< Frame buffer address.*/
- size_t wrap_offset; /**< Offset between lines, in pixels.*/
- dma2d_pixfmt_t fmt; /**< Pixel format.*/
- dma2d_color_t def_color; /**< Default color, RGB-888.*/
- uint8_t const_alpha; /**< Constant alpha factor.*/
- const dma2d_palcfg_t *palettep; /**< Palette specs, or @p NULL.*/
-} dma2d_laycfg_t;
-
-/**
- * @brief DMA2D driver configuration.
- */
-typedef struct DMA2DConfig {
- /* ISR callbacks.*/
- dma2d_isrcb_t cfgerr_isr; /**< Configuration error, or @p NULL.*/
- dma2d_isrcb_t paltrfdone_isr; /**< Palette transfer done, or @p NULL.*/
- dma2d_isrcb_t palacserr_isr; /**< Palette access error, or @p NULL.*/
- dma2d_isrcb_t trfwmark_isr; /**< Transfer watermark, or @p NULL.*/
- dma2d_isrcb_t trfdone_isr; /**< Transfer complete, or @p NULL.*/
- dma2d_isrcb_t trferr_isr; /**< Transfer error, or @p NULL.*/
-} DMA2DConfig;
-
-/**
- * @brief DMA2D driver state.
- */
-typedef enum dma2d_state_t {
- DMA2D_UNINIT = (0), /**< Not initialized.*/
- DMA2D_STOP = (1), /**< Stopped.*/
- DMA2D_READY = (2), /**< Ready.*/
- DMA2D_ACTIVE = (3), /**< Executing commands.*/
- DMA2D_PAUSED = (4), /**< Transfer suspended.*/
-} dma2d_state_t;
-
-/**
- * @brief DMA2D driver.
- */
-typedef struct DMA2DDriver {
- dma2d_state_t state; /**< Driver state.*/
- const DMA2DConfig *config; /**< Driver configuration.*/
-
- /* Multithreading stuff.*/
-#if (TRUE == DMA2D_USE_WAIT) || defined(__DOXYGEN__)
- thread_t *thread; /**< Waiting thread.*/
-#endif /* DMA2D_USE_WAIT */
-#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION)
-#if (TRUE == CH_CFG_USE_MUTEXES)
- mutex_t lock; /**< Multithreading lock.*/
-#elif (TRUE == CH_CFG_USE_SEMAPHORES)
- semaphore_t lock; /**< Multithreading lock.*/
-#endif
-#endif /* DMA2D_USE_MUTUAL_EXCLUSION */
-} DMA2DDriver;
-
-/** @} */
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
-
-/**
- * @brief Makes an ARGB-8888 value from byte components.
- *
- * @param[in] a alpha byte component
- * @param[in] r red byte component
- * @param[in] g green byte component
- * @param[in] b blue byte component
- *
- * @return color in ARGB-8888 format
- *
- * @api
- */
-#define dma2dMakeARGB8888(a, r, g, b) \
- ((((dma2d_color_t)(a) & 0xFF) << 24) | \
- (((dma2d_color_t)(r) & 0xFF) << 16) | \
- (((dma2d_color_t)(g) & 0xFF) << 8) | \
- (((dma2d_color_t)(b) & 0xFF) << 0))
-
-/**
- * @brief Compute bytes per pixel.
- * @details Computes the bytes per pixel for the specified pixel format.
- * Rounds to the ceiling.
- *
- * @param[in] fmt pixel format
- *
- * @return bytes per pixel
- *
- * @api
- */
-#define dma2dBytesPerPixel(fmt) \
- ((dma2dBitsPerPixel(fmt) + 7) >> 3)
-
-/**
- * @brief Compute pixel address.
- * @details Computes the buffer address of a pixel, given the buffer
- * specifications.
- *
- * @param[in] originp buffer origin address
- * @param[in] pitch buffer pitch, in bytes
- * @param[in] fmt buffer pixel format
- * @param[in] x horizontal pixel coordinate
- * @param[in] y vertical pixel coordinate
- *
- * @return pixel address
- *
- * @api
- */
-#define dma2dComputeAddress(originp, pitch, fmt, x, y) \
- ((void *)dma2dComputeAddressConst(originp, pitch, fmt, x, y))
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-extern DMA2DDriver DMA2DD1;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- /* Driver methods.*/
- void dma2dInit(void);
- void dma2dObjectInit(DMA2DDriver *dma2dp);
- dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp);
- dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp);
- void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp);
- void dma2dStop(DMA2DDriver *dma2dp);
-#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION)
- void dma2dAcquireBusS(DMA2DDriver *dma2dp);
- void dma2dAcquireBus(DMA2DDriver *dma2dp);
- void dma2dReleaseBusS(DMA2DDriver *dma2dp);
- void dma2dReleaseBus(DMA2DDriver *dma2dp);
-#endif /* DMA2D_USE_MUTUAL_EXCLUSION */
-
- /* Global methods.*/
- uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp);
- uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp);
- void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line);
- void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line);
- bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp);
- bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp);
- void dma2dEnableWatermarkI(DMA2DDriver *dma2dp);
- void dma2dEnableWatermark(DMA2DDriver *dma2dp);
- void dma2dDisableWatermarkI(DMA2DDriver *dma2dp);
- void dma2dDisableWatermark(DMA2DDriver *dma2dp);
- uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp);
- uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp);
- void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles);
- void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles);
- bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp);
- bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp);
- void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp);
- void dma2dEnableDeadTime(DMA2DDriver *dma2dp);
- void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp);
- void dma2dDisableDeadTime(DMA2DDriver *dma2dp);
-
- /* Job methods.*/
- dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp);
- dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp);
- void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode);
- void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode);
- void dma2dJobGetSizeI(DMA2DDriver *dma2dp,
- uint16_t *widthp, uint16_t *heightp);
- void dma2dJobGetSize(DMA2DDriver *dma2dp,
- uint16_t *widthp, uint16_t *heightp);
- void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height);
- void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height);
- bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp);
- bool dma2dJobIsExecuting(DMA2DDriver *dma2dp);
- void dma2dJobStartI(DMA2DDriver *dma2dp);
- void dma2dJobStart(DMA2DDriver *dma2dp);
- void dma2dJobExecuteS(DMA2DDriver *dma2dp);
- void dma2dJobExecute(DMA2DDriver *dma2dp);
- void dma2dJobSuspendI(DMA2DDriver *dma2dp);
- void dma2dJobSuspend(DMA2DDriver *dma2dp);
- void dma2dJobResumeI(DMA2DDriver *dma2dp);
- void dma2dJobResume(DMA2DDriver *dma2dp);
- void dma2dJobAbortI(DMA2DDriver *dma2dp);
- void dma2dJobAbort(DMA2DDriver *dma2dp);
-
- /* Background layer methods.*/
- void *dma2dBgGetAddressI(DMA2DDriver *dma2dp);
- void *dma2dBgGetAddress(DMA2DDriver *dma2dp);
- void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp);
- void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp);
- size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp);
- size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp);
- void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset);
- void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset);
- uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp);
- uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp);
- void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a);
- void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a);
- dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp);
- dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp);
- void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode);
- void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode);
- dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp);
- dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp);
- void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp);
- dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp);
- void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep);
- void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep);
- void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep);
- void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep);
- void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
- void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
-
- /* Foreground layer methods.*/
- void *dma2dFgGetAddressI(DMA2DDriver *dma2dp);
- void *dma2dFgGetAddress(DMA2DDriver *dma2dp);
- void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp);
- void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp);
- size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp);
- size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp);
- void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset);
- void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset);
- uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp);
- uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp);
- void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a);
- void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a);
- dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp);
- dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp);
- void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode);
- void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode);
- dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp);
- dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp);
- void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp);
- dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp);
- void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep);
- void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep);
- void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep);
- void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep);
- void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
- void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
-
- /* Output layer methods.*/
- void *dma2dOutGetAddressI(DMA2DDriver *dma2dp);
- void *dma2dOutGetAddress(DMA2DDriver *dma2dp);
- void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp);
- void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp);
- size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp);
- size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp);
- void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset);
- void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset);
- dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp);
- dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp);
- void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt);
- dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp);
- dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp);
- void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c);
- void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp);
- void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
- void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp);
-
- /* Helper functions.*/
- const void *dma2dComputeAddressConst(const void *originp, size_t pitch,
- dma2d_pixfmt_t fmt,
- uint16_t x, uint16_t y);
- bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt);
- size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt);
-#if (TRUE == DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__)
- dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt);
- dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt);
-#endif /* DMA2D_USE_SOFTWARE_CONVERSIONS */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STM32_DMA2D_USE_DMA2D */
-
-#endif /* _STM32_DMA2D_H_ */
-
-/** @} */
+/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_dma2d.h + * @brief DMA2D/Chrom-ART driver. + * + * @addtogroup dma2d + * @{ + */ + +#ifndef _STM32_DMA2D_H_ +#define _STM32_DMA2D_H_ + +/** + * @brief Using the DMA2D driver. + */ +#if !defined(STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) +#define STM32_DMA2D_USE_DMA2D (FALSE) +#endif + +#if (TRUE == STM32_DMA2D_USE_DMA2D) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name DMA2D job modes + * @{ + */ +#define DMA2D_JOB_COPY (0 << 16) /**< Copy, replace(FG only).*/ +#define DMA2D_JOB_CONVERT (1 << 16) /**< Copy, convert (FG + PFC).*/ +#define DMA2D_JOB_BLEND (2 << 16) /**< Copy, blend (FG + BG + PFC).*/ +#define DMA2D_JOB_CONST (3 << 16) /**< Default color only (FG REG).*/ +/** @} */ + +/** + * @name DMA2D enable flag + * @{ + */ +#define DMA2D_EF_ENABLE (1 << 0) /**< DMA2D enabled.*/ +#define DMA2D_EF_DITHER (1 << 16) /**< Dithering enabled.*/ +#define DMA2D_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ +#define DMA2D_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ +#define DMA2D_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ +#define DMA2D_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ + +/** Enable flags mask. */ +#define DMA2D_EF_MASK \ + (DMA2D_EF_ENABLE | DMA2D_EF_DITHER | DMA2D_EF_PIXCLK_INVERT | \ + DMA2D_EF_DATAEN_HIGH | DMA2D_EF_VSYNC_HIGH | DMA2D_EF_HSYNC_HIGH) +/** @} */ + +/** + * @name DMA2D layer enable flags + * @{ + */ +#define DMA2D_LEF_ENABLE (1 << 0) /**< Layer enabled*/ +#define DMA2D_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ +#define DMA2D_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ + +/** Layer enable flag masks. */ +#define DMA2D_LEF_MASK \ + (DMA2D_LEF_ENABLE | DMA2D_LEF_KEYING | DMA2D_LEF_PALETTE) +/** @} */ + +/** + * @name DMA2D pixel formats + * @{ + */ +#define DMA2D_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ +#define DMA2D_FMT_RGB888 (1) /**< RGB-888 format.*/ +#define DMA2D_FMT_RGB565 (2) /**< RGB-565 format.*/ +#define DMA2D_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ +#define DMA2D_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ +#define DMA2D_FMT_L8 (5) /**< L-8 format.*/ +#define DMA2D_FMT_AL44 (6) /**< AL-44 format.*/ +#define DMA2D_FMT_AL88 (7) /**< AL-88 format.*/ +#define DMA2D_FMT_L4 (8) /**< L-4 format.*/ +#define DMA2D_FMT_A8 (9) /**< A-8 format.*/ +#define DMA2D_FMT_A4 (10) /**< A-4 format.*/ +/** @} */ + +/** + * @name DMA2D pixel format aliased raw masks + * @{ + */ +#define DMA2D_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ +#define DMA2D_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ +#define DMA2D_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ +#define DMA2D_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ +#define DMA2D_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ +#define DMA2D_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ +#define DMA2D_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ +#define DMA2D_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ +#define DMA2D_XMASK_L4 (0x0000000F) /**< L-4 aliased mask.*/ +#define DMA2D_XMASK_A8 (0xFF000000) /**< A-8 aliased mask.*/ +#define DMA2D_XMASK_A4 (0xF0000000) /**< A-4 aliased mask.*/ +/** @} */ + +/** + * @name DMA2D alpha modes + * @{ + */ +#define DMA2D_ALPHA_KEEP (0x00000000) /**< Original alpha channel.*/ +#define DMA2D_ALPHA_REPLACE (0x00010000) /**< Replace with constant.*/ +#define DMA2D_ALPHA_MODULATE (0x00020000) /**< Modulate with constant.*/ +/** @} */ + +/** + * @name DMA2D parameter bounds + * @{ + */ + +#define DMA2D_MIN_PIXFMT_ID (0) /**< Minimum pixel format ID.*/ +#define DMA2D_MAX_PIXFMT_ID (11) /**< Maximum pixel format ID.*/ +#define DMA2D_MIN_OUTPIXFMT_ID (0) /**< Minimum output pixel format ID.*/ +#define DMA2D_MAX_OUTPIXFMT_ID (4) /**< Maximum output pixel format ID.*/ + +#define DMA2D_MAX_OFFSET ((1 << 14) - 1) + +#define DMA2D_MAX_PALETTE_LENGTH (256) /***/ + +#define DMA2D_MAX_WIDTH ((1 << 14) - 1) +#define DMA2D_MAX_HEIGHT ((1 << 16) - 1) + +#define DMA2D_MAX_WATERMARK_POS ((1 << 16) - 1) + +#define DMA2D_MAX_DEADTIME_CYCLES ((1 << 8) - 1) + +/** @} */ + +/** + * @name DMA2D basic ARGB-8888 colors. + * @{ + */ +/* Microsoft Windows default 16-color palette.*/ +#define DMA2D_COLOR_BLACK (0xFF000000) +#define DMA2D_COLOR_MAROON (0xFF800000) +#define DMA2D_COLOR_GREEN (0xFF008000) +#define DMA2D_COLOR_OLIVE (0xFF808000) +#define DMA2D_COLOR_NAVY (0xFF000080) +#define DMA2D_COLOR_PURPLE (0xFF800080) +#define DMA2D_COLOR_TEAL (0xFF008080) +#define DMA2D_COLOR_SILVER (0xFFC0C0C0) +#define DMA2D_COLOR_GRAY (0xFF808080) +#define DMA2D_COLOR_RED (0xFFFF0000) +#define DMA2D_COLOR_LIME (0xFF00FF00) +#define DMA2D_COLOR_YELLOW (0xFFFFFF00) +#define DMA2D_COLOR_BLUE (0xFF0000FF) +#define DMA2D_COLOR_FUCHSIA (0xFFFF00FF) +#define DMA2D_COLOR_AQUA (0xFF00FFFF) +#define DMA2D_COLOR_WHITE (0xFFFFFFFF) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name DMA2D configuration options + * @{ + */ + +/** + * @brief DMA2D event interrupt priority level setting. + */ +#if !defined(STM32_DMA2D_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_DMA2D_IRQ_PRIORITY (11) +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_WAIT) || defined(__DOXYGEN__) +#define DMA2D_USE_WAIT (TRUE) +#endif + +/** + * @brief Enables the @p dma2dAcquireBus() and @p dma2dReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define DMA2D_USE_MUTUAL_EXCLUSION (TRUE) +#endif + +/** + * @brief Provides software color conversion functions. + * @note Disabling this option saves both code and data space. + */ +#if !defined(DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) +#define DMA2D_USE_SOFTWARE_CONVERSIONS (TRUE) +#endif + +/** + * @brief Enables checks for DMA2D functions. + * @note Disabling this option saves both code and data space. + * @note Disabling checks by ChibiOS will automatically disable DMA2D checks. + */ +#if !defined(DMA2D_USE_CHECKS) || defined(__DOXYGEN__) +#define DMA2D_USE_CHECKS (TRUE) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (TRUE != STM32_HAS_DMA2D) +#error "DMA2D must be present when using the DMA2D subsystem" +#endif + +#if (TRUE != STM32_DMA2D_USE_DMA2D) && (TRUE != STM32_HAS_DMA2D) +#error "DMA2D not present in the selected device" +#endif + +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) +#error "DMA2D_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* Complex types forwarding.*/ +typedef union dma2d_coloralias_t dma2d_coloralias_t; +typedef struct dma2d_palcfg_t dma2d_palcfg_t; +typedef struct dma2d_laycfg_t dma2d_layercfg_t; +typedef struct DMA2DConfig DMA2DConfig; +typedef enum dma2d_state_t dma2d_state_t; +typedef struct DMA2DDriver DMA2DDriver; + +/** + * @name DMA2D Data types + * @{ + */ + +/** + * @brief DMA2D generic color. + */ +typedef uint32_t dma2d_color_t; + +/** + * @brief DMA2D color aliases. + * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). + * Padding fields are prefixed with <tt>'x'</tt>, and should be clear + * (all 0) before compression and set (all 1) after expansion. + */ +typedef union dma2d_coloralias_t { + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned a : 8; + } argb8888; /**< Mapped ARGB-8888 bits.*/ + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned xa : 8; + } rgb888; /**< Mapped RGB-888 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 2; + unsigned g : 6; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 8; + } rgb565; /**< Mapped RGB-565 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 3; + unsigned g : 5; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 7; + unsigned a : 1; + } argb1555; /**< Mapped ARGB-1555 values.*/ + struct { + unsigned xb : 4; + unsigned b : 4; + unsigned xg : 4; + unsigned g : 4; + unsigned xr : 4; + unsigned r : 4; + unsigned xa : 4; + unsigned a : 4; + } argb4444; /**< Mapped ARGB-4444 values.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned xa : 8; + } l8; /**< Mapped L-8 bits.*/ + struct { + unsigned xl : 4; + unsigned l : 4; + unsigned x : 16; + unsigned xa : 4; + unsigned a : 4; + } al44; /**< Mapped AL-44 bits.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned a : 8; + } al88; /**< Mapped AL-88 bits.*/ + struct { + unsigned l : 4; + unsigned xl : 4; + unsigned x : 16; + unsigned xa : 8; + } l4; /**< Mapped L-4 bits.*/ + struct { + unsigned x : 24; + unsigned a : 8; + } a8; /**< Mapped A-8 bits.*/ + struct { + unsigned x : 24; + unsigned xa : 4; + unsigned a : 4; + } a4; /**< Mapped A-4 bits.*/ + dma2d_color_t aliased; /**< Aliased raw bits.*/ +} dma2d_coloralias_t; + +/** + * @brief DMA2D job (transfer) mode. + */ +typedef uint32_t dma2d_jobmode_t; + +/** + * @brief DMA2D pixel format. + */ +typedef uint32_t dma2d_pixfmt_t; + +/** + * @brief DMA2D alpha mode. + */ +typedef uint32_t dma2d_amode_t; + +/** + * @brief DMA2D ISR callback. + */ +typedef void (*dma2d_isrcb_t)(DMA2DDriver *dma2dp); + +/** + * @brief DMA2D palette specifications. + */ +typedef struct dma2d_palcfg_t { + const void *colorsp; /**< Pointer to color entries.*/ + uint16_t length; /**< Number of color entries.*/ + dma2d_pixfmt_t fmt; /**< Format, RGB-888 or ARGB-8888.*/ +} dma2d_palcfg_t; + +/** + * @brief DMA2D layer specifications. + */ +typedef struct dma2d_layercfg_t { + void *bufferp; /**< Frame buffer address.*/ + size_t wrap_offset; /**< Offset between lines, in pixels.*/ + dma2d_pixfmt_t fmt; /**< Pixel format.*/ + dma2d_color_t def_color; /**< Default color, RGB-888.*/ + uint8_t const_alpha; /**< Constant alpha factor.*/ + const dma2d_palcfg_t *palettep; /**< Palette specs, or @p NULL.*/ +} dma2d_laycfg_t; + +/** + * @brief DMA2D driver configuration. + */ +typedef struct DMA2DConfig { + /* ISR callbacks.*/ + dma2d_isrcb_t cfgerr_isr; /**< Configuration error, or @p NULL.*/ + dma2d_isrcb_t paltrfdone_isr; /**< Palette transfer done, or @p NULL.*/ + dma2d_isrcb_t palacserr_isr; /**< Palette access error, or @p NULL.*/ + dma2d_isrcb_t trfwmark_isr; /**< Transfer watermark, or @p NULL.*/ + dma2d_isrcb_t trfdone_isr; /**< Transfer complete, or @p NULL.*/ + dma2d_isrcb_t trferr_isr; /**< Transfer error, or @p NULL.*/ +} DMA2DConfig; + +/** + * @brief DMA2D driver state. + */ +typedef enum dma2d_state_t { + DMA2D_UNINIT = (0), /**< Not initialized.*/ + DMA2D_STOP = (1), /**< Stopped.*/ + DMA2D_READY = (2), /**< Ready.*/ + DMA2D_ACTIVE = (3), /**< Executing commands.*/ + DMA2D_PAUSED = (4), /**< Transfer suspended.*/ +} dma2d_state_t; + +/** + * @brief DMA2D driver. + */ +typedef struct DMA2DDriver { + dma2d_state_t state; /**< Driver state.*/ + const DMA2DConfig *config; /**< Driver configuration.*/ + + /* Multithreading stuff.*/ +#if (TRUE == DMA2D_USE_WAIT) || defined(__DOXYGEN__) + thread_t *thread; /**< Waiting thread.*/ +#endif /* DMA2D_USE_WAIT */ +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + mutex_t lock; /**< Multithreading lock.*/ +#elif (TRUE == CH_CFG_USE_SEMAPHORES) + semaphore_t lock; /**< Multithreading lock.*/ +#endif +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ +} DMA2DDriver; + +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Makes an ARGB-8888 value from byte components. + * + * @param[in] a alpha byte component + * @param[in] r red byte component + * @param[in] g green byte component + * @param[in] b blue byte component + * + * @return color in ARGB-8888 format + * + * @api + */ +#define dma2dMakeARGB8888(a, r, g, b) \ + ((((dma2d_color_t)(a) & 0xFF) << 24) | \ + (((dma2d_color_t)(r) & 0xFF) << 16) | \ + (((dma2d_color_t)(g) & 0xFF) << 8) | \ + (((dma2d_color_t)(b) & 0xFF) << 0)) + +/** + * @brief Compute bytes per pixel. + * @details Computes the bytes per pixel for the specified pixel format. + * Rounds to the ceiling. + * + * @param[in] fmt pixel format + * + * @return bytes per pixel + * + * @api + */ +#define dma2dBytesPerPixel(fmt) \ + ((dma2dBitsPerPixel(fmt) + 7) >> 3) + +/** + * @brief Compute pixel address. + * @details Computes the buffer address of a pixel, given the buffer + * specifications. + * + * @param[in] originp buffer origin address + * @param[in] pitch buffer pitch, in bytes + * @param[in] fmt buffer pixel format + * @param[in] x horizontal pixel coordinate + * @param[in] y vertical pixel coordinate + * + * @return pixel address + * + * @api + */ +#define dma2dComputeAddress(originp, pitch, fmt, x, y) \ + ((void *)dma2dComputeAddressConst(originp, pitch, fmt, x, y)) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern DMA2DDriver DMA2DD1; + +#ifdef __cplusplus +extern "C" { +#endif + + /* Driver methods.*/ + void dma2dInit(void); + void dma2dObjectInit(DMA2DDriver *dma2dp); + dma2d_state_t dma2dGetStateI(DMA2DDriver *dma2dp); + dma2d_state_t dma2dGetState(DMA2DDriver *dma2dp); + void dma2dStart(DMA2DDriver *dma2dp, const DMA2DConfig *configp); + void dma2dStop(DMA2DDriver *dma2dp); +#if (TRUE == DMA2D_USE_MUTUAL_EXCLUSION) + void dma2dAcquireBusS(DMA2DDriver *dma2dp); + void dma2dAcquireBus(DMA2DDriver *dma2dp); + void dma2dReleaseBusS(DMA2DDriver *dma2dp); + void dma2dReleaseBus(DMA2DDriver *dma2dp); +#endif /* DMA2D_USE_MUTUAL_EXCLUSION */ + + /* Global methods.*/ + uint16_t dma2dGetWatermarkPosI(DMA2DDriver *dma2dp); + uint16_t dma2dGetWatermarkPos(DMA2DDriver *dma2dp); + void dma2dSetWatermarkPosI(DMA2DDriver *dma2dp, uint16_t line); + void dma2dSetWatermarkPos(DMA2DDriver *dma2dp, uint16_t line); + bool dma2dIsWatermarkEnabledI(DMA2DDriver *dma2dp); + bool dma2dIsWatermarkEnabled(DMA2DDriver *dma2dp); + void dma2dEnableWatermarkI(DMA2DDriver *dma2dp); + void dma2dEnableWatermark(DMA2DDriver *dma2dp); + void dma2dDisableWatermarkI(DMA2DDriver *dma2dp); + void dma2dDisableWatermark(DMA2DDriver *dma2dp); + uint32_t dma2dGetDeadTimeI(DMA2DDriver *dma2dp); + uint32_t dma2dGetDeadTime(DMA2DDriver *dma2dp); + void dma2dSetDeadTimeI(DMA2DDriver *dma2dp, uint32_t cycles); + void dma2dSetDeadTime(DMA2DDriver *dma2dp, uint32_t cycles); + bool dma2dIsDeadTimeEnabledI(DMA2DDriver *dma2dp); + bool dma2dIsDeadTimeEnabled(DMA2DDriver *dma2dp); + void dma2dEnableDeadTimeI(DMA2DDriver *dma2dp); + void dma2dEnableDeadTime(DMA2DDriver *dma2dp); + void dma2dDisableDeadTimeI(DMA2DDriver *dma2dp); + void dma2dDisableDeadTime(DMA2DDriver *dma2dp); + + /* Job methods.*/ + dma2d_jobmode_t dma2dJobGetModeI(DMA2DDriver *dma2dp); + dma2d_jobmode_t dma2dJobGetMode(DMA2DDriver *dma2dp); + void dma2dJobSetModeI(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); + void dma2dJobSetMode(DMA2DDriver *dma2dp, dma2d_jobmode_t mode); + void dma2dJobGetSizeI(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp); + void dma2dJobGetSize(DMA2DDriver *dma2dp, + uint16_t *widthp, uint16_t *heightp); + void dma2dJobSetSizeI(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); + void dma2dJobSetSize(DMA2DDriver *dma2dp, uint16_t width, uint16_t height); + bool dma2dJobIsExecutingI(DMA2DDriver *dma2dp); + bool dma2dJobIsExecuting(DMA2DDriver *dma2dp); + void dma2dJobStartI(DMA2DDriver *dma2dp); + void dma2dJobStart(DMA2DDriver *dma2dp); + void dma2dJobExecuteS(DMA2DDriver *dma2dp); + void dma2dJobExecute(DMA2DDriver *dma2dp); + void dma2dJobSuspendI(DMA2DDriver *dma2dp); + void dma2dJobSuspend(DMA2DDriver *dma2dp); + void dma2dJobResumeI(DMA2DDriver *dma2dp); + void dma2dJobResume(DMA2DDriver *dma2dp); + void dma2dJobAbortI(DMA2DDriver *dma2dp); + void dma2dJobAbort(DMA2DDriver *dma2dp); + + /* Background layer methods.*/ + void *dma2dBgGetAddressI(DMA2DDriver *dma2dp); + void *dma2dBgGetAddress(DMA2DDriver *dma2dp); + void dma2dBgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dBgSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dBgGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dBgGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dBgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dBgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + uint8_t dma2dBgGetConstantAlphaI(DMA2DDriver *dma2dp); + uint8_t dma2dBgGetConstantAlpha(DMA2DDriver *dma2dp); + void dma2dBgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); + void dma2dBgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); + dma2d_amode_t dma2dBgGetAlphaModeI(DMA2DDriver *dma2dp); + dma2d_amode_t dma2dBgGetAlphaMode(DMA2DDriver *dma2dp); + void dma2dBgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); + void dma2dBgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); + dma2d_pixfmt_t dma2dBgGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dBgGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dBgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dBgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dBgGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dBgGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dBgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dBgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dBgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dBgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dBgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dBgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dBgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dBgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dBgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dBgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Foreground layer methods.*/ + void *dma2dFgGetAddressI(DMA2DDriver *dma2dp); + void *dma2dFgGetAddress(DMA2DDriver *dma2dp); + void dma2dFgSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dFgSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dFgGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dFgGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dFgSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dFgSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + uint8_t dma2dFgGetConstantAlphaI(DMA2DDriver *dma2dp); + uint8_t dma2dFgGetConstantAlpha(DMA2DDriver *dma2dp); + void dma2dFgSetConstantAlphaI(DMA2DDriver *dma2dp, uint8_t a); + void dma2dFgSetConstantAlpha(DMA2DDriver *dma2dp, uint8_t a); + dma2d_amode_t dma2dFgGetAlphaModeI(DMA2DDriver *dma2dp); + dma2d_amode_t dma2dFgGetAlphaMode(DMA2DDriver *dma2dp); + void dma2dFgSetAlphaModeI(DMA2DDriver *dma2dp, dma2d_amode_t mode); + void dma2dFgSetAlphaMode(DMA2DDriver *dma2dp, dma2d_amode_t mode); + dma2d_pixfmt_t dma2dFgGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dFgGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dFgSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dFgSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dFgGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dFgGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dFgSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dFgSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dFgGetPaletteI(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dFgGetPalette(DMA2DDriver *dma2dp, dma2d_palcfg_t *palettep); + void dma2dFgSetPaletteS(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dFgSetPalette(DMA2DDriver *dma2dp, const dma2d_palcfg_t *palettep); + void dma2dFgGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dFgGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dFgSetConfigS(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dFgSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Output layer methods.*/ + void *dma2dOutGetAddressI(DMA2DDriver *dma2dp); + void *dma2dOutGetAddress(DMA2DDriver *dma2dp); + void dma2dOutSetAddressI(DMA2DDriver *dma2dp, void *bufferp); + void dma2dOutSetAddress(DMA2DDriver *dma2dp, void *bufferp); + size_t dma2dOutGetWrapOffsetI(DMA2DDriver *dma2dp); + size_t dma2dOutGetWrapOffset(DMA2DDriver *dma2dp); + void dma2dOutSetWrapOffsetI(DMA2DDriver *dma2dp, size_t offset); + void dma2dOutSetWrapOffset(DMA2DDriver *dma2dp, size_t offset); + dma2d_pixfmt_t dma2dOutGetPixelFormatI(DMA2DDriver *dma2dp); + dma2d_pixfmt_t dma2dOutGetPixelFormat(DMA2DDriver *dma2dp); + void dma2dOutSetPixelFormatI(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + void dma2dOutSetPixelFormat(DMA2DDriver *dma2dp, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dOutGetDefaultColorI(DMA2DDriver *dma2dp); + dma2d_color_t dma2dOutGetDefaultColor(DMA2DDriver *dma2dp); + void dma2dOutSetDefaultColorI(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dOutSetDefaultColor(DMA2DDriver *dma2dp, dma2d_color_t c); + void dma2dOutGetLayerI(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dOutGetLayer(DMA2DDriver *dma2dp, dma2d_laycfg_t *cfgp); + void dma2dOutSetConfigI(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + void dma2dOutSetConfig(DMA2DDriver *dma2dp, const dma2d_laycfg_t *cfgp); + + /* Helper functions.*/ + const void *dma2dComputeAddressConst(const void *originp, size_t pitch, + dma2d_pixfmt_t fmt, + uint16_t x, uint16_t y); + bool dma2dIsAligned(const void *bufferp, dma2d_pixfmt_t fmt); + size_t dma2dBitsPerPixel(dma2d_pixfmt_t fmt); +#if (TRUE == DMA2D_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + dma2d_color_t dma2dFromARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); + dma2d_color_t dma2dToARGB8888(dma2d_color_t c, dma2d_pixfmt_t fmt); +#endif /* DMA2D_USE_SOFTWARE_CONVERSIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_DMA2D_USE_DMA2D */ + +#endif /* _STM32_DMA2D_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c index 27bc429..fe48696 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c @@ -22,7 +22,7 @@ * @{ */ #include "hal.h" -#include "fsmc.h" +#include "hal_fsmc.h" #if (HAL_USE_FSMC == TRUE) || defined(__DOXYGEN__) diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h index 7889b01..7889b01 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc.h +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.h diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c index d8db8a6..95f47d5 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.c +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.c @@ -32,7 +32,7 @@ #if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) -#include "fsmc_sdram.h" +#include "hal_fsmc_sdram.h" /*===========================================================================*/ /* Driver local definitions. */ diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h index d5d5476..cef6772 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sdram.h +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sdram.h @@ -31,7 +31,7 @@ #if (defined(STM32F427xx) || defined(STM32F437xx) || \ defined(STM32F429xx) || defined(STM32F439xx)) -#include "fsmc.h" +#include "hal_fsmc.h" #if (STM32_USE_FSMC_SDRAM == TRUE) || defined(__DOXYGEN__) diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c index 2375738..6f710d4 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c @@ -22,7 +22,7 @@ * @{ */ #include "hal.h" -#include "fsmc_sram.h" +#include "hal_fsmc_sram.h" #if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) diff --git a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h index bf5c32a..529bdc7 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.h +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.h @@ -25,7 +25,7 @@ #ifndef _FSMC_SRAM_H_ #define _FSMC_SRAM_H_ -#include "fsmc.h" +#include "hal_fsmc.h" #if (STM32_USE_FSMC_SRAM == TRUE) || defined(__DOXYGEN__) diff --git a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c index b37c026..b37c026 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c diff --git a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h index c891fcc..8dca42f 100644 --- a/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.h +++ b/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.h @@ -25,7 +25,7 @@ #ifndef _NAND_LLD_H_ #define _NAND_LLD_H_ -#include "fsmc.h" +#include "hal_fsmc.h" #include "bitmap.h" #if (HAL_USE_NAND == TRUE) || defined(__DOXYGEN__) diff --git a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c index 7037a7c..e5f9a09 100644 --- a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c +++ b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c @@ -1,3792 +1,3792 @@ -/*
- Copyright (C) 2013-2015 Andrea Zoppi
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file stm32_ltdc.c
- * @brief LCD-TFT Controller Driver.
- */
-
-#include "ch.h"
-#include "hal.h"
-
-#include "stm32_ltdc.h"
-
-#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__)
-
-/* TODO: Check preconditions (e.g., LTDC is ready).*/
-
-/* Ignore annoying warning messages for actually safe code.*/
-#if defined(__GNUC__) && !defined(__DOXYGEN__)
-#pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-
-/**
- * @addtogroup ltdc
- * @{
- */
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-#if !defined(LTDC_LxBFCR_BF) && !defined(__DOXYGEN__)
-#define LTDC_LxBFCR_BF (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2)
-#endif
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-
-/**
- * @brief LTDC1 driver identifier.
- */
-LTDCDriver LTDCD1;
-
-/*===========================================================================*/
-/* Driver local variables and types. */
-/*===========================================================================*/
-
-/**
- * @brief Bits per pixel lookup table.
- */
-static const uint8_t ltdc_bpp[LTDC_MAX_PIXFMT_ID + 1] = {
- 32, /* LTDC_FMT_ARGB8888 */
- 24, /* LTDC_FMT_RGB888 */
- 16, /* LTDC_FMT_RGB565 */
- 16, /* LTDC_FMT_ARGB1555 */
- 16, /* LTDC_FMT_ARGB4444 */
- 8, /* LTDC_FMT_L8 */
- 8, /* LTDC_FMT_AL44 */
- 16 /* LTDC_FMT_AL88 */
-};
-
-/**
- * @brief Invalid frame.
- */
-static const ltdc_frame_t ltdc_invalid_frame = {
- NULL,
- 1,
- 1,
- 1,
- LTDC_FMT_L8
-};
-
-/**
- * @brief Invalid window.
- * @details Pixel size, located at the origin of the screen.
- */
-static const ltdc_window_t ltdc_invalid_window = {
- 0,
- 1,
- 0,
- 1
-};
-
-/**
- * @brief Default layer specifications.
- */
-static const ltdc_laycfg_t ltdc_default_laycfg = {
- <dc_invalid_frame,
- <dc_invalid_window,
- LTDC_COLOR_BLACK,
- 0x00,
- LTDC_COLOR_BLACK,
- NULL,
- 0,
- LTDC_BLEND_FIX1_FIX2,
- 0
-};
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/**
- * @brief Forces LTDC register reload.
- * @details Blocking function.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @sclass
- * @notapi
- */
-static void ltdc_force_reload_s(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(ltdcp == <DCD1);
-
- LTDC->SRCR |= LTDC_SRCR_IMR;
- while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR))
- chSchDoYieldS();
-}
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @name LTDC interrupt handlers
- * @{
- */
-
-/**
- * @brief LTDC event interrupt handler.
- *
- * @isr
- */
-OSAL_IRQ_HANDLER(STM32_LTDC_EV_HANDLER) {
-
- LTDCDriver *const ltdcp = <DCD1;
- thread_t *tp = NULL;
-
- OSAL_IRQ_PROLOGUE();
-
- /* Handle Line Interrupt ISR.*/
- if ((LTDC->ISR & LTDC_ISR_LIF) && (LTDC->IER & LTDC_IER_LIE)) {
- osalDbgAssert(ltdcp->config->line_isr != NULL, "invalid state");
- ltdcp->config->line_isr(ltdcp);
- LTDC->ICR |= LTDC_ICR_CLIF;
- }
-
- /* Handle Register Reload ISR.*/
- if ((LTDC->ISR & LTDC_ISR_RRIF) && (LTDC->IER & LTDC_IER_RRIE)) {
- if (ltdcp->config->rr_isr != NULL)
- ltdcp->config->rr_isr(ltdcp);
-
- osalSysLockFromISR();
- osalDbgAssert(ltdcp->state == LTDC_ACTIVE, "invalid state");
-#if (TRUE == LTDC_USE_WAIT)
- /* Wake the waiting thread up.*/
- if (ltdcp->thread != NULL) {
- tp = ltdcp->thread;
- ltdcp->thread = NULL;
- tp->u.rdymsg = MSG_OK;
- chSchReadyI(tp);
- }
-#endif /* LTDC_USE_WAIT */
- ltdcp->state = LTDC_READY;
- osalSysUnlockFromISR();
-
- LTDC->ICR |= LTDC_ICR_CRRIF;
- }
-
- OSAL_IRQ_EPILOGUE();
-}
-
-/**
- * @brief LTDC error interrupt handler.
- *
- * @isr
- */
-OSAL_IRQ_HANDLER(STM32_LTDC_ER_HANDLER) {
-
- static LTDCDriver *const ltdcp = <DCD1;
-
- OSAL_IRQ_PROLOGUE();
-
- /* Handle FIFO Underrun ISR.*/
- if ((LTDC->ISR & LTDC_ISR_FUIF) && (LTDC->IER & LTDC_IER_FUIE)) {
- osalDbgAssert(ltdcp->config->fuerr_isr != NULL, "invalid state");
- ltdcp->config->fuerr_isr(ltdcp);
- LTDC->ICR |= LTDC_ICR_CFUIF;
- }
-
- /* Handle Transfer Error ISR.*/
- if ((LTDC->ISR & LTDC_ISR_TERRIF) && (LTDC->IER & LTDC_IER_TERRIE)) {
- osalDbgAssert(ltdcp->config->terr_isr != NULL, "invalid state");
- ltdcp->config->terr_isr(ltdcp);
- LTDC->ICR |= LTDC_ICR_CTERRIF;
- }
-
- OSAL_IRQ_EPILOGUE();
-}
-
-/** @} */
-
-/**
- * @name LTDC driver-specific methods
- * @{
- */
-
-/**
- * @brief LTDC Driver initialization.
- * @details Initializes the LTDC subsystem and chosen drivers. Should be
- * called at board initialization.
- *
- * @init
- */
-void ltdcInit(void) {
-
- /* Reset the LTDC hardware module.*/
- rccResetLTDC();
-
- /* Enable the LTDC clock.*/
- RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (2 << 16); /* /8 */
- rccEnableLTDC(false);
-
- /* Driver struct initialization.*/
- ltdcObjectInit(<DCD1);
- LTDCD1.state = LTDC_STOP;
-}
-
-/**
- * @brief Initializes the standard part of a @p LTDCDriver structure.
- *
- * @param[out] ltdcp pointer to the @p LTDCDriver object
- *
- * @init
- */
-void ltdcObjectInit(LTDCDriver *ltdcp) {
-
- osalDbgCheck(ltdcp == <DCD1);
-
- ltdcp->state = LTDC_UNINIT;
- ltdcp->config = NULL;
- ltdcp->active_window = ltdc_invalid_window;
-#if (TRUE == LTDC_USE_WAIT)
- ltdcp->thread = NULL;
-#endif /* LTDC_USE_WAIT */
-#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION)
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxObjectInit(<dcp->lock);
-#else
- chSemObjectInit(<dcp->lock, 1);
-#endif
-#endif /* LTDC_USE_MUTUAL_EXCLUSION */
-}
-
-/**
- * @brief Get the driver state.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @retun driver state
- *
- * @iclass
- */
-ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
-
- return ltdcp->state;
-}
-
-/**
- * @brief Get the driver state.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @retun driver state
- *
- * @api
- */
-ltdc_state_t ltdcGetState(LTDCDriver *ltdcp) {
-
- ltdc_state_t state;
- osalSysLock();
- state = ltdcGetStateI(ltdcp);
- osalSysUnlock();
- return state;
-}
-
-/**
- * @brief Configures and activates the LTDC peripheral.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] configp pointer to the @p LTDCConfig object
- *
- * @api
- */
-void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp) {
-
- uint32_t hacc, vacc, flags;
-
- osalSysLock();
-
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(configp != NULL);
- osalDbgAssert(ltdcp->state == LTDC_STOP, "invalid state");
-
- ltdcp->config = configp;
-
- /* Turn off the controller and its interrupts.*/
- LTDC->GCR = 0;
- LTDC->IER = 0;
- ltdc_force_reload_s(ltdcp);
-
- /* Set synchronization params.*/
- osalDbgAssert(configp->hsync_width >= LTDC_MIN_HSYNC_WIDTH, "bounds");
- osalDbgAssert(configp->hsync_width <= LTDC_MAX_HSYNC_WIDTH, "bounds");
- osalDbgAssert(configp->vsync_height >= LTDC_MIN_VSYNC_HEIGHT, "bounds");
- osalDbgAssert(configp->vsync_height <= LTDC_MAX_VSYNC_HEIGHT, "bounds");
-
- hacc = configp->hsync_width - 1;
- vacc = configp->vsync_height - 1;
-
- LTDC->SSCR = (((hacc << 16) & LTDC_SSCR_HSW) |
- ((vacc << 0) & LTDC_SSCR_VSH));
-
- /* Set accumulated back porch params.*/
- osalDbgAssert(configp->hbp_width >= LTDC_MIN_HBP_WIDTH, "bounds");
- osalDbgAssert(configp->hbp_width <= LTDC_MAX_HBP_WIDTH, "bounds");
- osalDbgAssert(configp->vbp_height >= LTDC_MIN_VBP_HEIGHT, "bounds");
- osalDbgAssert(configp->vbp_height <= LTDC_MAX_VBP_HEIGHT, "bounds");
-
- hacc += configp->hbp_width;
- vacc += configp->vbp_height;
-
- osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_HBP_WIDTH, "bounds");
- osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_HBP_WIDTH, "bounds");
- osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_VBP_HEIGHT, "bounds");
- osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_VBP_HEIGHT, "bounds");
-
- LTDC->BPCR = (((hacc << 16) & LTDC_BPCR_AHBP) |
- ((vacc << 0) & LTDC_BPCR_AVBP));
-
- ltdcp->active_window.hstart = hacc + 1;
- ltdcp->active_window.vstart = vacc + 1;
-
- /* Set accumulated active params.*/
- osalDbgAssert(configp->screen_width >= LTDC_MIN_SCREEN_WIDTH, "bounds");
- osalDbgAssert(configp->screen_width <= LTDC_MAX_SCREEN_WIDTH, "bounds");
- osalDbgAssert(configp->screen_height >= LTDC_MIN_SCREEN_HEIGHT, "bounds");
- osalDbgAssert(configp->screen_height <= LTDC_MAX_SCREEN_HEIGHT, "bounds");
-
- hacc += configp->screen_width;
- vacc += configp->screen_height;
-
- osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_ACTIVE_WIDTH, "bounds");
- osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_ACTIVE_WIDTH, "bounds");
- osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_ACTIVE_HEIGHT, "bounds");
- osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_ACTIVE_HEIGHT, "bounds");
-
- LTDC->AWCR = (((hacc << 16) & LTDC_AWCR_AAW) |
- ((vacc << 0) & LTDC_AWCR_AAH));
-
- ltdcp->active_window.hstop = hacc;
- ltdcp->active_window.vstop = vacc;
-
- /* Set accumulated total params.*/
- osalDbgAssert(configp->hfp_width >= LTDC_MIN_HFP_WIDTH, "bounds");
- osalDbgAssert(configp->hfp_width <= LTDC_MAX_HFP_WIDTH, "bounds");
- osalDbgAssert(configp->vfp_height >= LTDC_MIN_VFP_HEIGHT, "bounds");
- osalDbgAssert(configp->vfp_height <= LTDC_MAX_VFP_HEIGHT, "bounds");
-
- hacc += configp->hfp_width;
- vacc += configp->vfp_height;
-
- osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_TOTAL_WIDTH, "bounds");
- osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_TOTAL_WIDTH, "bounds");
- osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_TOTAL_HEIGHT, "bounds");
- osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_TOTAL_HEIGHT, "bounds");
-
- LTDC->TWCR = (((hacc << 16) & LTDC_TWCR_TOTALW) |
- ((vacc << 0) & LTDC_TWCR_TOTALH));
-
- /* Set signal polarities and other flags.*/
- ltdcSetEnableFlagsI(ltdcp, configp->flags & ~LTDC_EF_ENABLE);
-
- /* Color settings.*/
- ltdcSetClearColorI(ltdcp, configp->clear_color);
-
- /* Load layer configurations.*/
- ltdcBgSetConfigI(ltdcp, configp->bg_laycfg);
- ltdcFgSetConfigI(ltdcp, configp->fg_laycfg);
-
- /* Enable only the assigned interrupt service routines.*/
- nvicEnableVector(STM32_LTDC_EV_NUMBER, STM32_LTDC_EV_IRQ_PRIORITY);
- nvicEnableVector(STM32_LTDC_ER_NUMBER, STM32_LTDC_ER_IRQ_PRIORITY);
-
- flags = LTDC_IER_RRIE;
- if (configp->line_isr != NULL)
- flags |= LTDC_IER_LIE;
- if (configp->fuerr_isr != NULL)
- flags |= LTDC_IER_FUIE;
- if (configp->terr_isr != NULL)
- flags |= LTDC_IER_TERRIE;
- LTDC->IER = flags;
-
- /* Apply settings.*/
- ltdc_force_reload_s(ltdcp);
-
- /* Turn on the controller.*/
- LTDC->GCR |= LTDC_GCR_LTDCEN;
- ltdc_force_reload_s(ltdcp);
-
- ltdcp->state = LTDC_READY;
- osalSysUnlock();
-}
-
-/**
- * @brief Deactivates the LTDC peripheral.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcStop(LTDCDriver *ltdcp) {
-
- osalDbgCheck(ltdcp == <DCD1);
-
- osalSysLock();
- osalDbgAssert(ltdcp->state == LTDC_READY, "invalid state");
-
- /* Turn off the controller and its interrupts.*/
- LTDC->GCR &= ~LTDC_GCR_LTDCEN;
- LTDC->IER = 0;
-#if (TRUE == LTDC_USE_WAIT)
- ltdcReloadS(ltdcp, true);
-#else
- ltdcStartReloadI(ltdcp, true);
- while (ltdcIsReloadingI(ltdcp))
- chSchDoYieldS();
-#endif /* LTDC_USE_WAIT */
-
- ltdcp->state = LTDC_STOP;
- osalSysUnlock();
-}
-
-#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION)
-
-/**
- * @brief Gains exclusive access to the LTDC module.
- * @details This function tries to gain ownership to the LTDC module, if the
- * module is already being used then the invoking thread is queued.
- * @pre In order to use this function the option
- * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @sclass
- */
-void ltdcAcquireBusS(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(ltdcp == <DCD1);
-
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxLockS(<dcp->lock);
-#else
- chSemWaitS(<dcp->lock);
-#endif
-}
-
-/**
- * @brief Gains exclusive access to the LTDC module.
- * @details This function tries to gain ownership to the LTDC module, if the
- * module is already being used then the invoking thread is queued.
- * @pre In order to use this function the option
- * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcAcquireBus(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcAcquireBusS(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Releases exclusive access to the LTDC module.
- * @pre In order to use this function the option
- * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @sclass
- */
-void ltdcReleaseBusS(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassS();
- osalDbgCheck(ltdcp == <DCD1);
-
-#if (TRUE == CH_CFG_USE_MUTEXES)
- chMtxUnlockS(<dcp->lock);
-#else
- chSemSignalI(<dcp->lock);
-#endif
-}
-
-/**
- * @brief Releases exclusive access to the LTDC module.
- * @pre In order to use this function the option
- * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcReleaseBus(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcReleaseBusS(ltdcp);
- osalSysUnlock();
-}
-
-#endif /* LTDC_USE_MUTUAL_EXCLUSION */
-
-/** @} */
-
-/**
- * @name LTDC global methods
- * @{
- */
-
-/**
- * @brief Get enabled flags.
- * @details Returns all the flags of the <tt>LTDC_EF_*</tt> group at once.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @iclass
- */
-ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return LTDC->GCR & LTDC_EF_MASK;
-}
-
-/**
- * @brief Get enabled flags.
- * @details Returns all the flags of the <tt>LTDC_EF_*</tt> group at once.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @api
- */
-ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp) {
-
- ltdc_flags_t flags;
- osalSysLock();
- flags = ltdcGetEnableFlagsI(ltdcp);
- osalSysUnlock();
- return flags;
-}
-
-/**
- * @brief Set enabled flags.
- * @details Sets all the flags of the <tt>LTDC_EF_*</tt> group at once.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @iclass
- */
-void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->GCR = flags & LTDC_EF_MASK;
-}
-
-/**
- * @brief Set enabled flags.
- * @details Sets all the flags of the <tt>LTDC_EF_*</tt> group at once.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @api
- */
-void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalSysLock();
- ltdcSetEnableFlagsI(ltdcp, flags);
- osalSysUnlock();
-}
-
-/**
- * @brief Reloading shadow registers.
- * @details Tells whether the LTDC is reloading shadow registers.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return reloading
- *
- * @iclass
- */
-bool ltdcIsReloadingI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) != 0;
-}
-
-/**
- * @brief Reloading shadow registers.
- * @details Tells whether the LTDC is reloading shadow registers.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return reloading
- *
- * @api
- */
-bool ltdcIsReloading(LTDCDriver *ltdcp) {
-
- bool reloading;
- osalSysLock();
- reloading = ltdcIsReloadingI(ltdcp);
- osalSysUnlock();
- return reloading;
-}
-
-/**
- * @brief Reload shadow registers.
- * @details Starts reloading LTDC shadow registers, upon vsync or immediately.
- * @post At the end of the operation the configured callback is invoked.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] immediately reload immediately, not upon vsync
- *
- * @iclass
- */
-void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgAssert(ltdcp->state == LTDC_READY, "not ready");
- (void)ltdcp;
-
- ltdcp->state = LTDC_ACTIVE;
- if (immediately)
- LTDC->SRCR |= LTDC_SRCR_IMR;
- else
- LTDC->SRCR |= LTDC_SRCR_VBR;
-}
-
-/**
- * @brief Reload shadow registers.
- * @details Starts reloading LTDC shadow registers, upon vsync or immediately.
- * @post At the end of the operation the configured callback is invoked.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] immediately reload immediately, not upon vsync
- *
- * @api
- */
-void ltdcStartReload(LTDCDriver *ltdcp, bool immediately) {
-
- osalSysLock();
- ltdcStartReloadI(ltdcp, immediately);
- osalSysUnlock();
-}
-
-/**
- * @brief Reload shadow registers.
- * @details Reloads LTDC shadow registers, upon vsync or immediately.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] immediately reload immediately, not upon vsync
- *
- * @sclass
- */
-void ltdcReloadS(LTDCDriver *ltdcp, bool immediately) {
-
- osalDbgCheckClassS();
- osalDbgCheck(ltdcp == <DCD1);
-
- ltdcStartReloadI(ltdcp, immediately);
-
-#if (TRUE == LTDC_USE_WAIT)
- osalDbgAssert(ltdcp->thread == NULL, "already waiting");
-
- if (immediately) {
- while (LTDC->SRCR & LTDC_SRCR_IMR)
- chSchDoYieldS();
- ltdcp->state = LTDC_READY;
- } else {
- ltdcp->thread = chThdGetSelfX();
- chSchGoSleepS(CH_STATE_SUSPENDED);
- }
-#else
- while (LTDC->SRCR & LTDC_SRCR_IMR)
- chSchDoYieldS();
- ltdcp->state = LTDC_READY;
-#endif
-}
-
-/**
- * @brief Reload shadow registers.
- * @details Reloads LTDC shadow registers, upon vsync or immediately.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] immediately reload immediately, not upon vsync
- *
- * @api
- */
-void ltdcReload(LTDCDriver *ltdcp, bool immediately) {
-
- osalSysLock();
- ltdcReloadS(ltdcp, immediately);
- osalSysUnlock();
-}
-
-/**
- * @brief Dithering enabled.
- * @details Tells whether the dithering is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC->GCR & LTDC_GCR_DTEN) != 0;
-}
-
-/**
- * @brief Dithering enabled.
- * @details Tells whether the dithering is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcIsDitheringEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable dithering.
- * @details Enables dithering capabilities for pixel formats with less than
- * 8 bits per channel.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcEnableDitheringI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->GCR |= LTDC_GCR_DTEN;
-}
-
-/**
- * @brief Enable dithering.
- * @details Enables dithering capabilities for pixel formats with less than
- * 8 bits per channel.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcEnableDithering(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcEnableDitheringI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable dithering.
- * @details Disables dithering capabilities for pixel formats with less than
- * 8 bits per channel.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcDisableDitheringI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->GCR &= ~LTDC_GCR_DTEN;
-}
-
-/**
- * @brief Disable dithering.
- * @details Disables dithering capabilities for pixel formats with less than
- * 8 bits per channel.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcDisableDithering(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcDisableDitheringI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get clear screen color.
- * @details Gets the clear screen (actual background) color.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return clear screen color, RGB-888
- *
- * @iclass
- */
-ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_color_t)(LTDC->BCCR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get clear screen color.
- * @details Gets the clear screen (actual background) color.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return clear screen color, RGB-888
- *
- * @api
- */
-ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp) {
-
- ltdc_color_t color;
- osalSysLock();
- color = ltdcGetClearColorI(ltdcp);
- osalSysUnlock();
- return color;
-}
-
-/**
- * @brief Set clear screen color.
- * @details Sets the clear screen (actual background) color.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c clear screen color, RGB-888
- *
- * @iclass
- */
-void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (c & 0x00FFFFFF);
-}
-
-/**
- * @brief Set clear screen color.
- * @details Sets the clear screen (actual background) color.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c clear screen color, RGB-888
- *
- * @api
- */
-void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalSysLock();
- ltdcSetClearColorI(ltdcp, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Get line interrupt position.
- * @details Gets the line interrupt position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return line interrupt position
- *
- * @iclass
- */
-uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (uint16_t)(LTDC->LIPCR & LTDC_LIPCR_LIPOS);
-}
-
-/**
- * @brief Get line interrupt position.
- * @details Gets the line interrupt position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return line interrupt position
- *
- * @api
- */
-uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp) {
-
- uint16_t line;
- osalSysLock();
- line = ltdcGetLineInterruptPosI(ltdcp);
- osalSysUnlock();
- return line;
-}
-
-/**
- * @brief Set line interrupt position.
- * @details Sets the line interrupt position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->LIPCR = ((LTDC->LIPCR & ~LTDC_LIPCR_LIPOS) |
- ((uint32_t)line & LTDC_LIPCR_LIPOS));
-}
-
-/**
- * @brief Set line interrupt position.
- * @details Sets the line interrupt position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line) {
-
- osalSysLock();
- ltdcSetLineInterruptPosI(ltdcp, line);
- osalSysUnlock();
-}
-
-/**
- * @brief Line interrupt enabled.
- * @details Tells whether the line interrupt is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC->IER & LTDC_IER_LIE) != 0;
-}
-
-/**
- * @brief Line interrupt enabled.
- * @details Tells whether the line interrupt is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcIsLineInterruptEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable line interrupt.
- * @details Enables line interrupt.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcEnableLineInterruptI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->IER |= LTDC_IER_LIE;
-}
-
-/**
- * @brief Enable line interrupt.
- * @details Enables line interrupt.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcEnableLineInterrupt(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcEnableLineInterruptI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable line interrupt.
- * @details Disables line interrupt.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcDisableLineInterruptI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC->IER &= ~LTDC_IER_LIE;
-}
-
-/**
- * @brief Disable line interrupt.
- * @details Disables line interrupt.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcDisableLineInterrupt(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcDisableLineInterruptI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get current position.
- * @details Gets the current position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] xp pointer to the destination horizontal coordinate
- * @param[out] yp pointer to the destination vertical coordinate
- *
- * @iclass
- */
-void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) {
-
- const uint32_t r = LTDC->CPSR;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- *xp = (uint16_t)((r & LTDC_CPSR_CXPOS) >> 16);
- *yp = (uint16_t)((r & LTDC_CPSR_CYPOS) >> 0);
-}
-
-/**
- * @brief Get current position.
- * @details Gets the current position.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] xp pointer to the destination horizontal coordinate
- * @param[out] yp pointer to the destination vertical coordinate
- *
- * @api
- */
-void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) {
-
- osalSysLock();
- ltdcGetCurrentPosI(ltdcp, xp, yp);
- osalSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name LTDC background layer (layer 1) methods
- * @{
- */
-
-/**
- * @brief Get background layer enabled flags.
- * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @iclass
- */
-ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return LTDC_Layer1->CR & LTDC_LEF_MASK;
-}
-
-/**
- * @brief Get background layer enabled flags.
- * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @api
- */
-ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp) {
-
- ltdc_flags_t flags;
- osalSysLock();
- flags = ltdcBgGetEnableFlagsI(ltdcp);
- osalSysUnlock();
- return flags;
-}
-
-/**
- * @brief Set background layer enabled flags.
- * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @iclass
- */
-void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR = ((LTDC_Layer1->CR & ~LTDC_LEF_MASK) |
- ((uint32_t)flags & LTDC_LEF_MASK));
-}
-
-/**
- * @brief Set background layer enabled flags.
- * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @api
- */
-void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalSysLock();
- ltdcBgSetEnableFlagsI(ltdcp, flags);
- osalSysUnlock();
-}
-
-/**
- * @brief Background layer enabled.
- * @details Tells whether the background layer (layer 1) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcBgIsEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer1->CR & ~LTDC_LxCR_LEN) != 0;
-}
-
-/**
- * @brief Background layer enabled.
- * @details Tells whether the background layer (layer 1) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcBgIsEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcBgIsEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Background layer enable.
- * @details Enables the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgEnableI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR |= LTDC_LxCR_LEN;
-}
-
-/**
- * @brief Background layer enable.
- * @details Enables the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgEnable(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgEnableI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Background layer disable.
- * @details Disables the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgDisableI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR &= ~LTDC_LxCR_LEN;
-}
-
-/**
- * @brief Background layer disable.
- * @details Disables the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgDisable(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgDisableI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Background layer palette enabled.
- * @details Tells whether the background layer (layer 1) palette (color lookup
- * table) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer1->CR & ~LTDC_LxCR_CLUTEN) != 0;
-}
-
-/**
- * @brief Background layer palette enabled.
- * @details Tells whether the background layer (layer 1) palette (color lookup
- * table) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcBgIsPaletteEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable background layer palette.
- * @details Enables the palette (color lookup table) of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgEnablePaletteI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR |= LTDC_LxCR_CLUTEN;
-}
-
-/**
- * @brief Enable background layer palette.
- * @details Enables the palette (color lookup table) of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgEnablePalette(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgEnablePaletteI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable background layer palette.
- * @details Disables the palette (color lookup table) of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgDisablePaletteI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR &= ~LTDC_LxCR_CLUTEN;
-}
-
-/**
- * @brief Disable background layer palette.
- * @details Disables the palette (color lookup table) of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgDisablePalette(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgDisablePaletteI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer palette color.
- * @details Sets the color of a palette (color lookup table) slot to the
- * background layer (layer 1).
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] slot palette slot
- * @param[in] c color, RGB-888
- *
- * @iclass
- */
-void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state");
- (void)ltdcp;
-
- LTDC_Layer1->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF));
-}
-
-/**
- * @brief Set background layer palette color.
- * @details Sets the color of a palette (color lookup table) slot to the
- * background layer (layer 1).
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] slot palette slot
- * @param[in] c color, RGB-888
- *
- * @api
- */
-void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) {
-
- osalSysLock();
- ltdcBgSetPaletteColorI(ltdcp, slot, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer palette.
- * @details Sets the entire palette color (color lookup table) slot.
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] colors array of palette colors, RGB-888
- * @param[in] length number of palette colors
- *
- * @iclass
- */
-void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length) {
-
- uint16_t i;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck((colors == NULL) == (length == 0));
- osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds");
- osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state");
- (void)ltdcp;
-
- for (i = 0; i < length; ++i)
- LTDC_Layer1->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF));
-}
-
-/**
- * @brief Set background layer palette.
- * @details Sets the entire palette color (color lookup table) slot.
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] colors array of palette colors, RGB-888
- * @param[in] length number of palette colors
- *
- * @api
- */
-void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length) {
-
- osalSysLock();
- ltdcBgSetPaletteI(ltdcp, colors, length);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer pixel format.
- * @details Gets the pixel format of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return pixel format
- *
- * @iclass
- */
-ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_pixfmt_t)(LTDC_Layer1->PFCR & LTDC_LxPFCR_PF);
-}
-
-/**
- * @brief Get background layer pixel format.
- * @details Gets the pixel format of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return pixel format
- *
- * @api
- */
-ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp) {
-
- ltdc_pixfmt_t fmt;
- osalSysLock();
- fmt = ltdcBgGetPixelFormatI(ltdcp);
- osalSysUnlock();
- return fmt;
-}
-
-/**
- * @brief Set background layer pixel format.
- * @details Sets the pixel format of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] fmt pixel format
- *
- * @iclass
- */
-void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds");
- osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds");
- (void)ltdcp;
-
- LTDC_Layer1->PFCR = ((LTDC_Layer1->PFCR & ~LTDC_LxPFCR_PF) |
- ((uint32_t)fmt & LTDC_LxPFCR_PF));
-}
-
-/**
- * @brief Set background layer pixel format.
- * @details Sets the pixel format of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] fmt pixel format
- *
- * @api
- */
-void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) {
-
- osalSysLock();
- ltdcBgSetPixelFormatI(ltdcp, fmt);
- osalSysUnlock();
-}
-
-/**
- * @brief Background layer color keying enabled.
- * @details Tells whether the background layer (layer 1) has color keying
- * enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer1->CR & ~LTDC_LxCR_COLKEN) != 0;
-}
-
-/**
- * @brief Background layer color keying enabled.
- * @details Tells whether the background layer (layer 1) has color keying
- * enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcBgIsKeyingEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable background layer color keying.
- * @details Enables color keying capabilities of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgEnableKeyingI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR |= LTDC_LxCR_COLKEN;
-}
-
-/**
- * @brief Enable background layer color keying.
- * @details Enables color keying capabilities of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgEnableKeying(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgEnableKeyingI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable background layer color keying.
- * @details Disables color keying capabilities of the background layer (layer
- * 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgDisableKeyingI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CR &= ~LTDC_LxCR_COLKEN;
-}
-
-/**
- * @brief Disable background layer color keying.
- * @details Disables color keying capabilities of the background layer (layer
- * 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgDisableKeying(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgDisableKeyingI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer color key.
- * @details Gets the color key of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return color key, RGB-888
- *
- * @iclass
- */
-ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_color_t)(LTDC_Layer1->CKCR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get background layer color key.
- * @details Gets the color key of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return color key, RGB-888
- *
- * @api
- */
-ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp) {
-
- ltdc_color_t color;
- osalSysLock();
- color = ltdcBgGetKeyingColorI(ltdcp);
- osalSysUnlock();
- return color;
-}
-
-/**
- * @brief Set background layer color key.
- * @details Sets the color key of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c color key, RGB-888
- *
- * @iclass
- */
-void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CKCR = ((LTDC_Layer1->CKCR & ~0x00FFFFFF) |
- ((uint32_t)c & 0x00FFFFFF));
-}
-
-/**
- * @brief Set background layer color key.
- * @details Sets the color key of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c color key, RGB-888
- *
- * @api
- */
-void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalSysLock();
- ltdcBgSetKeyingColorI(ltdcp, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer constant alpha.
- * @details Gets the constant alpha component of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return constant alpha component, A-8
- *
- * @iclass
- */
-uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (uint8_t)(LTDC_Layer1->CACR & LTDC_LxCACR_CONSTA);
-}
-
-/**
- * @brief Get background layer constant alpha.
- * @details Gets the constant alpha component of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return constant alpha component, A-8
- *
- * @api
- */
-uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp) {
-
- uint8_t a;
- osalSysLock();
- a = ltdcBgGetConstantAlphaI(ltdcp);
- osalSysUnlock();
- return a;
-}
-
-/**
- * @brief Set background layer constant alpha.
- * @details Sets the constant alpha component of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @iclass
- */
-void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CACR = ((LTDC_Layer1->CACR & ~LTDC_LxCACR_CONSTA) |
- ((uint32_t)a & LTDC_LxCACR_CONSTA));
-}
-
-/**
- * @brief Set background layer constant alpha.
- * @details Sets the constant alpha component of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @api
- */
-void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) {
-
- osalSysLock();
- ltdcBgSetConstantAlphaI(ltdcp, a);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer default color.
- * @details Gets the default color of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return default color, RGB-888
- *
- * @iclass
- */
-ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_color_t)LTDC_Layer1->DCCR;
-}
-
-/**
- * @brief Get background layer default color.
- * @details Gets the default color of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return default color, RGB-888
- *
- * @api
- */
-ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp) {
-
- ltdc_color_t color;
- osalSysLock();
- color = ltdcBgGetDefaultColorI(ltdcp);
- osalSysUnlock();
- return color;
-}
-
-/**
- * @brief Set background layer default color.
- * @details Sets the default color of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c default color, RGB-888
- *
- * @iclass
- */
-void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->DCCR = (uint32_t)c;
-}
-
-/**
- * @brief Set background layer default color.
- * @details Sets the default color of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c default color, RGB-888
- *
- * @api
- */
-void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalSysLock();
- ltdcBgSetDefaultColorI(ltdcp, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer blending factors.
- * @details Gets the blending factors of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return blending factors
- *
- * @iclass
- */
-ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_blendf_t)(LTDC_Layer1->BFCR & LTDC_LxBFCR_BF);
-}
-
-/**
- * @brief Get background layer blending factors.
- * @details Gets the blending factors of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return blending factors
- *
- * @api
- */
-ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp) {
-
- ltdc_blendf_t bf;
- osalSysLock();
- bf = ltdcBgGetBlendingFactorsI(ltdcp);
- osalSysUnlock();
- return bf;
-}
-
-/**
- * @brief Set background layer blending factors.
- * @details Sets the blending factors of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] factors blending factors
- *
- * @iclass
- */
-void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->BFCR = ((LTDC_Layer1->BFCR & ~LTDC_LxBFCR_BF) |
- ((uint32_t)bf & LTDC_LxBFCR_BF));
-}
-
-/**
- * @brief Set background layer blending factors.
- * @details Sets the blending factors of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] factors blending factors
- *
- * @api
- */
-void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) {
-
- osalSysLock();
- ltdcBgSetBlendingFactorsI(ltdcp, bf);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer window specs.
- * @details Gets the window specifications of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] windowp pointer to the window specifications
- *
- * @iclass
- */
-void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(windowp != NULL);
- (void)ltdcp;
-
- windowp->hstart =
- (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0);
- windowp->hstop =
- (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16);
- windowp->vstart =
- (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0);
- windowp->vstop =
- (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16);
-}
-
-/**
- * @brief Get background layer window specs.
- * @details Gets the window specifications of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] windowp pointer to the window specifications
- *
- * @api
- */
-void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) {
-
- osalSysLock();
- ltdcBgGetWindowI(ltdcp, windowp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer window specs.
- * @details Sets the window specifications of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] windowp pointer to the window specifications
- *
- * @iclass
- */
-void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) {
-
- uint32_t start, stop;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(windowp != NULL);
- (void)ltdcp;
-
- osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds");
- osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds");
-
- /* Horizontal boundaries.*/
- start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart;
- stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart;
-
- osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds");
- osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds");
-
- LTDC_Layer1->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) |
- ((stop << 16) & LTDC_LxWHPCR_WHSPPOS));
-
- /* Vertical boundaries.*/
- start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart;
- stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart;
-
- osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds");
- osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds");
-
- LTDC_Layer1->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) |
- ((stop << 16) & LTDC_LxWVPCR_WVSPPOS));
-}
-
-/**
- * @brief Set background layer window specs.
- * @details Sets the window specifications of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] windowp pointer to the window specifications
- *
- * @api
- */
-void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) {
-
- osalSysLock();
- ltdcBgSetWindowI(ltdcp, windowp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer window as invalid.
- * @details Sets the window specifications of the background layer (layer 1)
- * so that the window is pixel sized at the screen origin.
- * @note Useful before reconfiguring the frame specifications of the layer,
- * to avoid errors.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp) {
-
- ltdcBgSetWindowI(ltdcp, <dc_invalid_window);
-}
-
-/**
- * @brief Set background layer window as invalid.
- * @details Sets the window specifications of the background layer (layer 1)
- * so that the window is pixel sized at the screen origin.
- * @note Useful before reconfiguring the frame specifications of the layer,
- * to avoid errors.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcBgSetWindowI(ltdcp, <dc_invalid_window);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer frame buffer specs.
- * @details Gets the frame buffer specifications of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] framep pointer to the frame buffer specifications
- *
- * @iclass
- */
-void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(framep != NULL);
-
- framep->bufferp = (void *)(LTDC_Layer1->CFBAR & LTDC_LxCFBAR_CFBADD);
- framep->pitch = (size_t)((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBP) >> 16);
- framep->width = (uint16_t)(((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) /
- ltdcBytesPerPixel(ltdcBgGetPixelFormatI(ltdcp)));
- framep->height = (uint16_t)(LTDC_Layer1->CFBLNR & LTDC_LxCFBLNR_CFBLNBR);
-}
-
-/**
- * @brief Get background layer frame buffer specs.
- * @details Gets the frame buffer specifications of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] framep pointer to the frame buffer specifications
- *
- * @api
- */
-void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) {
-
- osalSysLock();
- ltdcBgGetFrameI(ltdcp, framep);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer frame buffer specs.
- * @details Sets the frame buffer specifications of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] framep pointer to the frame buffer specifications
- *
- * @iclass
- */
-void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) {
-
- size_t linesize;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(framep != NULL);
-
- ltdcBgSetPixelFormatI(ltdcp, framep->fmt);
-
- linesize = ltdcBytesPerPixel(framep->fmt) * framep->width;
-
- osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds");
- osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds");
- osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds");
- osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds");
- osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds");
- osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds");
- osalDbgAssert(framep->pitch >= linesize, "bounds");
-
- LTDC_Layer1->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD;
- LTDC_Layer1->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) |
- ((linesize + 3) & LTDC_LxCFBLR_CFBLL));
- LTDC_Layer1->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR;
-}
-
-/**
- * @brief Set background layer frame buffer specs.
- * @details Sets the frame buffer specifications of the background layer
- * (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] framep pointer to the frame buffer specifications
- *
- * @api
- */
-void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) {
-
- osalSysLock();
- ltdcBgSetFrameI(ltdcp, framep);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer frame buffer address.
- * @details Gets the frame buffer address of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return frame buffer address
- *
- * @iclass
- */
-void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (void *)LTDC_Layer1->CFBAR;
-}
-
-/**
- * @brief Get background layer frame buffer address.
- * @details Gets the frame buffer address of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return frame buffer address
- *
- * @api
- */
-void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp) {
-
- void *bufferp;
- osalSysLock();
- bufferp = ltdcBgGetFrameAddressI(ltdcp);
- osalSysUnlock();
- return bufferp;
-}
-
-/**
- * @brief Set background layer frame buffer address.
- * @details Sets the frame buffer address of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] bufferp frame buffer address
- *
- * @iclass
- */
-void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer1->CFBAR = (uint32_t)bufferp;
-}
-
-/**
- * @brief Set background layer frame buffer address.
- * @details Sets the frame buffer address of the background layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] bufferp frame buffer address
- *
- * @api
- */
-void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) {
-
- osalSysLock();
- ltdcBgSetFrameAddressI(ltdcp, bufferp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get background layer specifications.
- * @details Gets the background layer (layer 1) specifications at once.
- * @note If palette specifications cannot be retrieved, they are set to
- * @p NULL. This is not an error.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(cfgp != NULL);
-
- ltdcBgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame);
- ltdcBgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window);
- cfgp->def_color = ltdcBgGetDefaultColorI(ltdcp);
- cfgp->key_color = ltdcBgGetKeyingColorI(ltdcp);
- cfgp->const_alpha = ltdcBgGetConstantAlphaI(ltdcp);
- cfgp->blending = ltdcBgGetBlendingFactorsI(ltdcp);
-
- cfgp->pal_colors = NULL;
- cfgp->pal_length = 0;
-
- cfgp->flags = ltdcBgGetEnableFlagsI(ltdcp);
-}
-
-/**
- * @brief Get background layer specifications.
- * @details Gets the background layer (layer 1) specifications at once.
- * @note If palette specifications cannot be retrieved, they are set to
- * @p NULL. This is not an error.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @api
- */
-void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) {
-
- osalSysLock();
- ltdcBgGetLayerI(ltdcp, cfgp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set background layer specifications.
- * @details Sets the background layer (layer 1) specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
-
- if (cfgp == NULL)
- cfgp = <dc_default_laycfg;
-
- osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0));
-
- ltdcBgSetFrameI(ltdcp, cfgp->frame);
- ltdcBgSetWindowI(ltdcp, cfgp->window);
- ltdcBgSetDefaultColorI(ltdcp, cfgp->def_color);
- ltdcBgSetKeyingColorI(ltdcp, cfgp->key_color);
- ltdcBgSetConstantAlphaI(ltdcp, cfgp->const_alpha);
- ltdcBgSetBlendingFactorsI(ltdcp, cfgp->blending);
-
- if (cfgp->pal_length > 0)
- ltdcBgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length);
-
- ltdcBgSetEnableFlagsI(ltdcp, cfgp->flags);
-}
-
-/**
- * @brief Set background layer specifications.
- * @details Sets the background layer (layer 1) specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @api
- */
-void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) {
-
- osalSysLock();
- ltdcBgSetConfigI(ltdcp, cfgp);
- osalSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name LTDC foreground layer (layer 2) methods
- * @{
- */
-
-/**
- * @brief Get foreground layer enabled flags.
- * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @iclass
- */
-ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return LTDC_Layer2->CR & LTDC_LEF_MASK;
-}
-
-/**
- * @brief Get foreground layer enabled flags.
- * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled flags
- *
- * @api
- */
-ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp) {
-
- ltdc_flags_t flags;
- osalSysLock();
- flags = ltdcFgGetEnableFlagsI(ltdcp);
- osalSysUnlock();
- return flags;
-}
-
-/**
- * @brief Set foreground layer enabled flags.
- * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @iclass
- */
-void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR = ((LTDC_Layer2->CR & ~LTDC_LEF_MASK) |
- ((uint32_t)flags & LTDC_LEF_MASK));
-}
-
-/**
- * @brief Set foreground layer enabled flags.
- * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once.
- * Targeting the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] flags enabled flags
- *
- * @api
- */
-void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) {
-
- osalSysLock();
- ltdcFgSetEnableFlagsI(ltdcp, flags);
- osalSysUnlock();
-}
-
-/**
- * @brief Foreground layer enabled.
- * @details Tells whether the foreground layer (layer 2) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcFgIsEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer2->CR & ~LTDC_LxCR_LEN) != 0;
-}
-
-/**
- * @brief Foreground layer enabled.
- * @details Tells whether the foreground layer (layer 2) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcFgIsEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcFgIsEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Foreground layer enable.
- * @details Enables the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgEnableI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR |= LTDC_LxCR_LEN;
-}
-
-/**
- * @brief Foreground layer enable.
- * @details Enables the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgEnable(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgEnableI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Foreground layer disable.
- * @details Disables the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgDisableI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR &= ~LTDC_LxCR_LEN;
-}
-
-/**
- * @brief Foreground layer disable.
- * @details Disables the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgDisable(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgDisableI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Foreground layer palette enabled.
- * @details Tells whether the foreground layer (layer 2) palette (color lookup
- * table) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer2->CR & ~LTDC_LxCR_CLUTEN) != 0;
-}
-
-/**
- * @brief Foreground layer palette enabled.
- * @details Tells whether the foreground layer (layer 2) palette (color lookup
- * table) is enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcFgIsPaletteEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable foreground layer palette.
- * @details Enables the palette (color lookup table) of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgEnablePaletteI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR |= LTDC_LxCR_CLUTEN;
-}
-
-/**
- * @brief Enable foreground layer palette.
- * @details Enables the palette (color lookup table) of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgEnablePalette(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgEnablePaletteI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable foreground layer palette.
- * @details Disables the palette (color lookup table) of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgDisablePaletteI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR &= ~LTDC_LxCR_CLUTEN;
-}
-
-/**
- * @brief Disable foreground layer palette.
- * @details Disables the palette (color lookup table) of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgDisablePalette(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgDisablePaletteI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer palette color.
- * @details Sets the color of a palette (color lookup table) slot to the
- * foreground layer (layer 2).
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] slot palette slot
- * @param[in] c color, RGB-888
- *
- * @iclass
- */
-void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state");
- (void)ltdcp;
-
- LTDC_Layer2->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF));
-}
-
-/**
- * @brief Set foreground layer palette color.
- * @details Sets the color of a palette (color lookup table) slot to the
- * foreground layer (layer 2).
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] slot palette slot
- * @param[in] c color, RGB-888
- *
- * @api
- */
-void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) {
-
- osalSysLock();
- ltdcFgSetPaletteColorI(ltdcp, slot, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer palette.
- * @details Sets the entire palette color (color lookup table) slot.
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] colors array of palette colors, RGB-888
- * @param[in] length number of palette colors
- *
- * @iclass
- */
-void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length) {
-
- uint16_t i;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck((colors == NULL) == (length == 0));
- osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds");
- osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state");
- (void)ltdcp;
-
- for (i = 0; i < length; ++i)
- LTDC_Layer2->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF));
-}
-
-/**
- * @brief Set foreground layer palette.
- * @details Sets the entire palette color (color lookup table) slot.
- * @pre The layer must be disabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] colors array of palette colors, RGB-888
- * @param[in] length number of palette colors
- *
- * @api
- */
-void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length) {
-
- osalSysLock();
- ltdcFgSetPaletteI(ltdcp, colors, length);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer pixel format.
- * @details Gets the pixel format of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return pixel format
- *
- * @iclass
- */
-ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_pixfmt_t)(LTDC_Layer2->PFCR & LTDC_LxPFCR_PF);
-}
-
-/**
- * @brief Get foreground layer pixel format.
- * @details Gets the pixel format of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return pixel format
- *
- * @api
- */
-ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp) {
-
- ltdc_pixfmt_t fmt;
- osalSysLock();
- fmt = ltdcFgGetPixelFormatI(ltdcp);
- osalSysUnlock();
- return fmt;
-}
-
-/**
- * @brief Set foreground layer pixel format.
- * @details Sets the pixel format of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] fmt pixel format
- *
- * @iclass
- */
-void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds");
- osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds");
- (void)ltdcp;
-
- LTDC_Layer2->PFCR = ((LTDC_Layer2->PFCR & ~LTDC_LxPFCR_PF) |
- ((uint32_t)fmt & LTDC_LxPFCR_PF));
-}
-
-/**
- * @brief Set foreground layer pixel format.
- * @details Sets the pixel format of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] fmt pixel format
- *
- * @api
- */
-void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) {
-
- osalSysLock();
- ltdcFgSetPixelFormatI(ltdcp, fmt);
- osalSysUnlock();
-}
-
-/**
- * @brief Foreground layer color keying enabled.
- * @details Tells whether the foreground layer (layer 2) has color keying
- * enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @iclass
- */
-bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (LTDC_Layer2->CR & ~LTDC_LxCR_COLKEN) != 0;
-}
-
-/**
- * @brief Foreground layer color keying enabled.
- * @details Tells whether the foreground layer (layer 2) has color keying
- * enabled.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return enabled
- *
- * @api
- */
-bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp) {
-
- bool enabled;
- osalSysLock();
- enabled = ltdcFgIsKeyingEnabledI(ltdcp);
- osalSysUnlock();
- return enabled;
-}
-
-/**
- * @brief Enable foreground layer color keying.
- * @details Enables color keying capabilities of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgEnableKeyingI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR |= LTDC_LxCR_COLKEN;
-}
-
-/**
- * @brief Enable foreground layer color keying.
- * @details Enables color keying capabilities of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgEnableKeying(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgEnableKeyingI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Disable foreground layer color keying.
- * @details Disables color keying capabilities of the foreground layer (layer
- * 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgDisableKeyingI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CR &= ~LTDC_LxCR_COLKEN;
-}
-
-/**
- * @brief Disable foreground layer color keying.
- * @details Disables color keying capabilities of the foreground layer (layer
- * 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgDisableKeying(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgDisableKeyingI(ltdcp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer color key.
- * @details Gets the color key of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return color key, RGB-888
- *
- * @iclass
- */
-ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_color_t)(LTDC_Layer2->CKCR & 0x00FFFFFF);
-}
-
-/**
- * @brief Get foreground layer color key.
- * @details Gets the color key of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return color key, RGB-888
- *
- * @api
- */
-ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp) {
-
- ltdc_color_t color;
- osalSysLock();
- color = ltdcFgGetKeyingColorI(ltdcp);
- osalSysUnlock();
- return color;
-}
-
-/**
- * @brief Set foreground layer color key.
- * @details Sets the color key of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c color key, RGB-888
- *
- * @iclass
- */
-void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CKCR = ((LTDC_Layer2->CKCR & ~0x00FFFFFF) |
- ((uint32_t)c & 0x00FFFFFF));
-}
-
-/**
- * @brief Set foreground layer color key.
- * @details Sets the color key of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c color key, RGB-888
- *
- * @api
- */
-void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalSysLock();
- ltdcFgSetKeyingColorI(ltdcp, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer constant alpha.
- * @details Gets the constant alpha component of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return constant alpha component, A-8
- *
- * @iclass
- */
-uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (uint8_t)(LTDC_Layer2->CACR & LTDC_LxCACR_CONSTA);
-}
-
-/**
- * @brief Get foreground layer constant alpha.
- * @details Gets the constant alpha component of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return constant alpha component, A-8
- *
- * @api
- */
-uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp) {
-
- uint8_t a;
- osalSysLock();
- a = ltdcFgGetConstantAlphaI(ltdcp);
- osalSysUnlock();
- return a;
-}
-
-/**
- * @brief Set foreground layer constant alpha.
- * @details Sets the constant alpha component of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @iclass
- */
-void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CACR = ((LTDC_Layer2->CACR & ~LTDC_LxCACR_CONSTA) |
- ((uint32_t)a & LTDC_LxCACR_CONSTA));
-}
-
-/**
- * @brief Set foreground layer constant alpha.
- * @details Sets the constant alpha component of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] a constant alpha component, A-8
- *
- * @api
- */
-void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) {
-
- osalSysLock();
- ltdcFgSetConstantAlphaI(ltdcp, a);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer default color.
- * @details Gets the default color of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return default color, RGB-888
- *
- * @iclass
- */
-ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_color_t)LTDC_Layer2->DCCR;
-}
-
-/**
- * @brief Get foreground layer default color.
- * @details Gets the default color of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return default color, RGB-888
- *
- * @api
- */
-ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp) {
-
- ltdc_color_t color;
- osalSysLock();
- color = ltdcFgGetDefaultColorI(ltdcp);
- osalSysUnlock();
- return color;
-}
-
-/**
- * @brief Set foreground layer default color.
- * @details Sets the default color of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c default color, RGB-888
- *
- * @iclass
- */
-void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->DCCR = (uint32_t)c;
-}
-
-/**
- * @brief Set foreground layer default color.
- * @details Sets the default color of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] c default color, RGB-888
- *
- * @api
- */
-void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) {
-
- osalSysLock();
- ltdcFgSetDefaultColorI(ltdcp, c);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer blending factors.
- * @details Gets the blending factors of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return blending factors
- *
- * @iclass
- */
-ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (ltdc_blendf_t)(LTDC_Layer2->BFCR & LTDC_LxBFCR_BF);
-}
-
-/**
- * @brief Get foreground layer blending factors.
- * @details Gets the blending factors of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return blending factors
- *
- * @api
- */
-ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp) {
-
- ltdc_blendf_t bf;
- osalSysLock();
- bf = ltdcFgGetBlendingFactorsI(ltdcp);
- osalSysUnlock();
- return bf;
-}
-
-/**
- * @brief Set foreground layer blending factors.
- * @details Sets the blending factors of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] factors blending factors
- *
- * @iclass
- */
-void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->BFCR = ((LTDC_Layer2->BFCR & ~LTDC_LxBFCR_BF) |
- ((uint32_t)bf & LTDC_LxBFCR_BF));
-}
-
-/**
- * @brief Set foreground layer blending factors.
- * @details Sets the blending factors of the foreground layer (layer 1).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] factors blending factors
- *
- * @api
- */
-void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) {
-
- osalSysLock();
- ltdcFgSetBlendingFactorsI(ltdcp, bf);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer window specs.
- * @details Gets the window specifications of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] windowp pointer to the window specifications
- *
- * @iclass
- */
-void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(windowp != NULL);
- (void)ltdcp;
-
- windowp->hstart =
- (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0);
- windowp->hstop =
- (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16);
- windowp->vstart =
- (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0);
- windowp->vstop =
- (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16);
-}
-
-/**
- * @brief Get foreground layer window specs.
- * @details Gets the window specifications of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] windowp pointer to the window specifications
- *
- * @api
- */
-void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) {
-
- osalSysLock();
- ltdcFgGetWindowI(ltdcp, windowp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer window specs.
- * @details Sets the window specifications of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] windowp pointer to the window specifications
- *
- * @iclass
- */
-void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) {
-
- uint32_t start, stop;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(windowp != NULL);
- (void)ltdcp;
-
- osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds");
- osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds");
-
- /* Horizontal boundaries.*/
- start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart;
- stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart;
-
- osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds");
- osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds");
-
- LTDC_Layer2->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) |
- ((stop << 16) & LTDC_LxWHPCR_WHSPPOS));
-
- /* Vertical boundaries.*/
- start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart;
- stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart;
-
- osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds");
- osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds");
-
- LTDC_Layer2->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) |
- ((stop << 16) & LTDC_LxWVPCR_WVSPPOS));
-}
-
-/**
- * @brief Set foreground layer window specs.
- * @details Sets the window specifications of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] windowp pointer to the window specifications
- *
- * @api
- */
-void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) {
-
- osalSysLock();
- ltdcFgSetWindowI(ltdcp, windowp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer window as invalid.
- * @details Sets the window specifications of the foreground layer (layer 2)
- * so that the window is pixel sized at the screen origin.
- * @note Useful before reconfiguring the frame specifications of the layer,
- * to avoid errors.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @iclass
- */
-void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp) {
-
- ltdcFgSetWindowI(ltdcp, <dc_invalid_window);
-}
-
-/**
- * @brief Set foreground layer window as invalid.
- * @details Sets the window specifications of the foreground layer (layer 2)
- * so that the window is pixel sized at the screen origin.
- * @note Useful before reconfiguring the frame specifications of the layer,
- * to avoid errors.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @api
- */
-void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp) {
-
- osalSysLock();
- ltdcFgSetWindowI(ltdcp, <dc_invalid_window);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer frame buffer specs.
- * @details Gets the frame buffer specifications of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] framep pointer to the frame buffer specifications
- *
- * @iclass
- */
-void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(framep != NULL);
-
- framep->bufferp = (void *)(LTDC_Layer2->CFBAR & LTDC_LxCFBAR_CFBADD);
- framep->pitch = (size_t)((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBP) >> 16);
- framep->width = (uint16_t)(((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) /
- ltdcBytesPerPixel(ltdcFgGetPixelFormatI(ltdcp)));
- framep->height = (uint16_t)(LTDC_Layer2->CFBLNR & LTDC_LxCFBLNR_CFBLNBR);
-}
-
-/**
- * @brief Get foreground layer frame buffer specs.
- * @details Gets the frame buffer specifications of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] framep pointer to the frame buffer specifications
- *
- * @api
- */
-void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) {
-
- osalSysLock();
- ltdcFgGetFrameI(ltdcp, framep);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer frame buffer specs.
- * @details Sets the frame buffer specifications of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] framep pointer to the frame buffer specifications
- *
- * @iclass
- */
-void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) {
-
- size_t linesize;
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(framep != NULL);
-
- ltdcFgSetPixelFormatI(ltdcp, framep->fmt);
-
- linesize = ltdcBytesPerPixel(framep->fmt) * framep->width;
-
- osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds");
- osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds");
- osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds");
- osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds");
- osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds");
- osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds");
- osalDbgAssert(framep->pitch >= linesize, "bounds");
-
- LTDC_Layer2->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD;
- LTDC_Layer2->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) |
- ((linesize + 3) & LTDC_LxCFBLR_CFBLL));
- LTDC_Layer2->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR;
-}
-
-/**
- * @brief Set foreground layer frame buffer specs.
- * @details Sets the frame buffer specifications of the foreground layer
- * (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] framep pointer to the frame buffer specifications
- *
- * @api
- */
-void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) {
-
- osalSysLock();
- ltdcFgSetFrameI(ltdcp, framep);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer frame buffer address.
- * @details Gets the frame buffer address of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return frame buffer address
- *
- * @iclass
- */
-void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- return (void *)LTDC_Layer2->CFBAR;
-}
-
-/**
- * @brief Get foreground layer frame buffer address.
- * @details Gets the frame buffer address of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- *
- * @return frame buffer address
- *
- * @api
- */
-void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp) {
-
- void *bufferp;
- osalSysLock();
- bufferp = ltdcFgGetFrameAddressI(ltdcp);
- osalSysUnlock();
- return bufferp;
-}
-
-/**
- * @brief Set foreground layer frame buffer address.
- * @details Sets the frame buffer address of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] bufferp frame buffer address
- *
- * @iclass
- */
-void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- (void)ltdcp;
-
- LTDC_Layer2->CFBAR = (uint32_t)bufferp;
-}
-
-/**
- * @brief Set foreground layer frame buffer address.
- * @details Sets the frame buffer address of the foreground layer (layer 2).
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] bufferp frame buffer address
- *
- * @api
- */
-void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) {
-
- osalSysLock();
- ltdcFgSetFrameAddressI(ltdcp, bufferp);
- osalSysUnlock();
-}
-
-/**
- * @brief Get foreground layer specifications.
- * @details Gets the foreground layer (layer 2) specifications at once.
- * @note If palette specifications cannot be retrieved, they are set to
- * @p NULL. This is not an error.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
- osalDbgCheck(cfgp != NULL);
-
- ltdcFgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame);
- ltdcFgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window);
- cfgp->def_color = ltdcFgGetDefaultColorI(ltdcp);
- cfgp->key_color = ltdcFgGetKeyingColorI(ltdcp);
- cfgp->const_alpha = ltdcFgGetConstantAlphaI(ltdcp);
- cfgp->blending = ltdcFgGetBlendingFactorsI(ltdcp);
-
- cfgp->pal_colors = NULL;
- cfgp->pal_length = 0;
-
- cfgp->flags = ltdcFgGetEnableFlagsI(ltdcp);
-}
-
-/**
- * @brief Get foreground layer specifications.
- * @details Gets the foreground layer (layer 2) specifications at once.
- * @note If palette specifications cannot be retrieved, they are set to
- * @p NULL. This is not an error.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[out] cfgp pointer to the layer specifications
- *
- * @api
- */
-void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) {
-
- osalSysLock();
- ltdcFgGetLayerI(ltdcp, cfgp);
- osalSysUnlock();
-}
-
-/**
- * @brief Set foreground layer specifications.
- * @details Sets the foreground layer (layer 2) specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @iclass
- */
-void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) {
-
- osalDbgCheckClassI();
- osalDbgCheck(ltdcp == <DCD1);
-
- if (cfgp == NULL)
- cfgp = <dc_default_laycfg;
-
- osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0));
-
- ltdcFgSetFrameI(ltdcp, cfgp->frame);
- ltdcFgSetWindowI(ltdcp, cfgp->window);
- ltdcFgSetDefaultColorI(ltdcp, cfgp->def_color);
- ltdcFgSetKeyingColorI(ltdcp, cfgp->key_color);
- ltdcFgSetConstantAlphaI(ltdcp, cfgp->const_alpha);
- ltdcFgSetBlendingFactorsI(ltdcp, cfgp->blending);
-
- if (cfgp->pal_length > 0)
- ltdcFgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length);
-
- ltdcFgSetEnableFlagsI(ltdcp, cfgp->flags);
-}
-
-/**
- * @brief Set foreground layer specifications.
- * @details Sets the foreground layer (layer 2) specifications at once.
- * @note If the palette is unspecified, the layer palette is unmodified.
- *
- * @param[in] ltdcp pointer to the @p LTDCDriver object
- * @param[in] cfgp pointer to the layer specifications
- *
- * @api
- */
-void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) {
-
- osalSysLock();
- ltdcFgSetConfigI(ltdcp, cfgp);
- osalSysUnlock();
-}
-
-/** @} */
-
-/**
- * @name LTDC helper functions
- */
-
-/**
- * @brief Compute bits per pixel.
- * @details Computes the bits per pixel for the specified pixel format.
- *
- * @param[in] fmt pixel format
- *
- * @retuen bits per pixel
- *
- * @api
- */
-size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt) {
-
- osalDbgAssert(fmt < LTDC_MAX_PIXFMT_ID, "invalid format");
-
- return (size_t)ltdc_bpp[(unsigned)fmt];
-}
-
-#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__)
-
-/**
- * @brief Convert from ARGB-8888.
- * @details Converts an ARGB-8888 color to the specified pixel format.
- *
- * @param[in] c color, ARGB-8888
- * @param[in] fmt target pixel format
- *
- * @return raw color value for the target pixel format, left
- * padded with zeros.
- *
- * @api
- */
-ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) {
-
- switch (fmt) {
- case LTDC_FMT_ARGB8888: {
- return c;
- }
- case LTDC_FMT_RGB888: {
- return (c & 0x00FFFFFF);
- }
- case LTDC_FMT_RGB565: {
- return (((c & 0x000000F8) >> ( 8 - 5)) |
- ((c & 0x0000FC00) >> (16 - 11)) |
- ((c & 0x00F80000) >> (24 - 16)));
- }
- case LTDC_FMT_ARGB1555: {
- return (((c & 0x000000F8) >> ( 8 - 5)) |
- ((c & 0x0000F800) >> (16 - 10)) |
- ((c & 0x00F80000) >> (24 - 15)) |
- ((c & 0x80000000) >> (32 - 16)));
- }
- case LTDC_FMT_ARGB4444: {
- return (((c & 0x000000F0) >> ( 8 - 4)) |
- ((c & 0x0000F000) >> (16 - 8)) |
- ((c & 0x00F00000) >> (24 - 12)) |
- ((c & 0xF0000000) >> (32 - 16)));
- }
- case LTDC_FMT_L8: {
- return (c & 0x000000FF);
- }
- case LTDC_FMT_AL44: {
- return (((c & 0x000000F0) >> ( 8 - 4)) |
- ((c & 0xF0000000) >> (32 - 8)));
- }
- case LTDC_FMT_AL88: {
- return (((c & 0x000000FF) >> ( 8 - 8)) |
- ((c & 0xFF000000) >> (32 - 16)));
- }
- default:
- osalDbgAssert(false, "invalid format");
- return 0;
- }
-}
-
-/**
- * @brief Convert to ARGB-8888.
- * @details Converts color of the specified pixel format to an ARGB-8888 color.
- *
- * @param[in] c color for the source pixel format, left padded with
- * zeros.
- * @param[in] fmt source pixel format
- *
- * @return color in ARGB-8888 format
- *
- * @api
- */
-ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) {
-
- switch (fmt) {
- case LTDC_FMT_ARGB8888: {
- return c;
- }
- case LTDC_FMT_RGB888: {
- return ((c & 0x00FFFFFF) | 0xFF000000);
- }
- case LTDC_FMT_RGB565: {
- register ltdc_color_t output = 0xFF000000;
- if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007);
- if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300);
- if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000);
- return output;
- }
- case LTDC_FMT_ARGB1555: {
- register ltdc_color_t output = 0x00000000;
- if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007);
- if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700);
- if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000);
- if (c & 0x8000) output |= 0xFF000000;
- return output;
- }
- case LTDC_FMT_ARGB4444: {
- register ltdc_color_t output = 0x00000000;
- if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F);
- if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00);
- if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000);
- if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000);
- return output;
- }
- case LTDC_FMT_L8: {
- return ((c & 0xFF) | 0xFF000000);
- }
- case LTDC_FMT_AL44: {
- register ltdc_color_t output = 0x00000000;
- if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F);
- if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000);
- return output;
- }
- case LTDC_FMT_AL88: {
- return (((c & 0x00FF) << ( 8 - 8)) |
- ((c & 0xFF00) << (32 - 16)));
- }
- default:
- osalDbgAssert(false, "invalid format");
- return 0;
- }
-}
-
-#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */
-
-/** @} */
-
-/** @} */
-
-#endif /* STM32_LTDC_USE_LTDC */
+/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_ltdc.c + * @brief LCD-TFT Controller Driver. + */ + +#include "ch.h" +#include "hal.h" + +#include "hal_stm32_ltdc.h" + +#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) + +/* TODO: Check preconditions (e.g., LTDC is ready).*/ + +/* Ignore annoying warning messages for actually safe code.*/ +#if defined(__GNUC__) && !defined(__DOXYGEN__) +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +/** + * @addtogroup ltdc + * @{ + */ + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#if !defined(LTDC_LxBFCR_BF) && !defined(__DOXYGEN__) +#define LTDC_LxBFCR_BF (LTDC_LxBFCR_BF1 | LTDC_LxBFCR_BF2) +#endif + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief LTDC1 driver identifier. + */ +LTDCDriver LTDCD1; + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/** + * @brief Bits per pixel lookup table. + */ +static const uint8_t ltdc_bpp[LTDC_MAX_PIXFMT_ID + 1] = { + 32, /* LTDC_FMT_ARGB8888 */ + 24, /* LTDC_FMT_RGB888 */ + 16, /* LTDC_FMT_RGB565 */ + 16, /* LTDC_FMT_ARGB1555 */ + 16, /* LTDC_FMT_ARGB4444 */ + 8, /* LTDC_FMT_L8 */ + 8, /* LTDC_FMT_AL44 */ + 16 /* LTDC_FMT_AL88 */ +}; + +/** + * @brief Invalid frame. + */ +static const ltdc_frame_t ltdc_invalid_frame = { + NULL, + 1, + 1, + 1, + LTDC_FMT_L8 +}; + +/** + * @brief Invalid window. + * @details Pixel size, located at the origin of the screen. + */ +static const ltdc_window_t ltdc_invalid_window = { + 0, + 1, + 0, + 1 +}; + +/** + * @brief Default layer specifications. + */ +static const ltdc_laycfg_t ltdc_default_laycfg = { + <dc_invalid_frame, + <dc_invalid_window, + LTDC_COLOR_BLACK, + 0x00, + LTDC_COLOR_BLACK, + NULL, + 0, + LTDC_BLEND_FIX1_FIX2, + 0 +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Forces LTDC register reload. + * @details Blocking function. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + * @notapi + */ +static void ltdc_force_reload_s(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + + LTDC->SRCR |= LTDC_SRCR_IMR; + while (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) + chSchDoYieldS(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @name LTDC interrupt handlers + * @{ + */ + +/** + * @brief LTDC event interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LTDC_EV_HANDLER) { + + LTDCDriver *const ltdcp = <DCD1; + thread_t *tp = NULL; + + OSAL_IRQ_PROLOGUE(); + + /* Handle Line Interrupt ISR.*/ + if ((LTDC->ISR & LTDC_ISR_LIF) && (LTDC->IER & LTDC_IER_LIE)) { + osalDbgAssert(ltdcp->config->line_isr != NULL, "invalid state"); + ltdcp->config->line_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CLIF; + } + + /* Handle Register Reload ISR.*/ + if ((LTDC->ISR & LTDC_ISR_RRIF) && (LTDC->IER & LTDC_IER_RRIE)) { + if (ltdcp->config->rr_isr != NULL) + ltdcp->config->rr_isr(ltdcp); + + osalSysLockFromISR(); + osalDbgAssert(ltdcp->state == LTDC_ACTIVE, "invalid state"); +#if (TRUE == LTDC_USE_WAIT) + /* Wake the waiting thread up.*/ + if (ltdcp->thread != NULL) { + tp = ltdcp->thread; + ltdcp->thread = NULL; + tp->u.rdymsg = MSG_OK; + chSchReadyI(tp); + } +#endif /* LTDC_USE_WAIT */ + ltdcp->state = LTDC_READY; + osalSysUnlockFromISR(); + + LTDC->ICR |= LTDC_ICR_CRRIF; + } + + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief LTDC error interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(STM32_LTDC_ER_HANDLER) { + + static LTDCDriver *const ltdcp = <DCD1; + + OSAL_IRQ_PROLOGUE(); + + /* Handle FIFO Underrun ISR.*/ + if ((LTDC->ISR & LTDC_ISR_FUIF) && (LTDC->IER & LTDC_IER_FUIE)) { + osalDbgAssert(ltdcp->config->fuerr_isr != NULL, "invalid state"); + ltdcp->config->fuerr_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CFUIF; + } + + /* Handle Transfer Error ISR.*/ + if ((LTDC->ISR & LTDC_ISR_TERRIF) && (LTDC->IER & LTDC_IER_TERRIE)) { + osalDbgAssert(ltdcp->config->terr_isr != NULL, "invalid state"); + ltdcp->config->terr_isr(ltdcp); + LTDC->ICR |= LTDC_ICR_CTERRIF; + } + + OSAL_IRQ_EPILOGUE(); +} + +/** @} */ + +/** + * @name LTDC driver-specific methods + * @{ + */ + +/** + * @brief LTDC Driver initialization. + * @details Initializes the LTDC subsystem and chosen drivers. Should be + * called at board initialization. + * + * @init + */ +void ltdcInit(void) { + + /* Reset the LTDC hardware module.*/ + rccResetLTDC(); + + /* Enable the LTDC clock.*/ + RCC->DCKCFGR = (RCC->DCKCFGR & ~RCC_DCKCFGR_PLLSAIDIVR) | (2 << 16); /* /8 */ + rccEnableLTDC(false); + + /* Driver struct initialization.*/ + ltdcObjectInit(<DCD1); + LTDCD1.state = LTDC_STOP; +} + +/** + * @brief Initializes the standard part of a @p LTDCDriver structure. + * + * @param[out] ltdcp pointer to the @p LTDCDriver object + * + * @init + */ +void ltdcObjectInit(LTDCDriver *ltdcp) { + + osalDbgCheck(ltdcp == <DCD1); + + ltdcp->state = LTDC_UNINIT; + ltdcp->config = NULL; + ltdcp->active_window = ltdc_invalid_window; +#if (TRUE == LTDC_USE_WAIT) + ltdcp->thread = NULL; +#endif /* LTDC_USE_WAIT */ +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxObjectInit(<dcp->lock); +#else + chSemObjectInit(<dcp->lock, 1); +#endif +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ +} + +/** + * @brief Get the driver state. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @retun driver state + * + * @iclass + */ +ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + return ltdcp->state; +} + +/** + * @brief Get the driver state. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @retun driver state + * + * @api + */ +ltdc_state_t ltdcGetState(LTDCDriver *ltdcp) { + + ltdc_state_t state; + osalSysLock(); + state = ltdcGetStateI(ltdcp); + osalSysUnlock(); + return state; +} + +/** + * @brief Configures and activates the LTDC peripheral. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] configp pointer to the @p LTDCConfig object + * + * @api + */ +void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp) { + + uint32_t hacc, vacc, flags; + + osalSysLock(); + + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(configp != NULL); + osalDbgAssert(ltdcp->state == LTDC_STOP, "invalid state"); + + ltdcp->config = configp; + + /* Turn off the controller and its interrupts.*/ + LTDC->GCR = 0; + LTDC->IER = 0; + ltdc_force_reload_s(ltdcp); + + /* Set synchronization params.*/ + osalDbgAssert(configp->hsync_width >= LTDC_MIN_HSYNC_WIDTH, "bounds"); + osalDbgAssert(configp->hsync_width <= LTDC_MAX_HSYNC_WIDTH, "bounds"); + osalDbgAssert(configp->vsync_height >= LTDC_MIN_VSYNC_HEIGHT, "bounds"); + osalDbgAssert(configp->vsync_height <= LTDC_MAX_VSYNC_HEIGHT, "bounds"); + + hacc = configp->hsync_width - 1; + vacc = configp->vsync_height - 1; + + LTDC->SSCR = (((hacc << 16) & LTDC_SSCR_HSW) | + ((vacc << 0) & LTDC_SSCR_VSH)); + + /* Set accumulated back porch params.*/ + osalDbgAssert(configp->hbp_width >= LTDC_MIN_HBP_WIDTH, "bounds"); + osalDbgAssert(configp->hbp_width <= LTDC_MAX_HBP_WIDTH, "bounds"); + osalDbgAssert(configp->vbp_height >= LTDC_MIN_VBP_HEIGHT, "bounds"); + osalDbgAssert(configp->vbp_height <= LTDC_MAX_VBP_HEIGHT, "bounds"); + + hacc += configp->hbp_width; + vacc += configp->vbp_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_HBP_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_HBP_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_VBP_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_VBP_HEIGHT, "bounds"); + + LTDC->BPCR = (((hacc << 16) & LTDC_BPCR_AHBP) | + ((vacc << 0) & LTDC_BPCR_AVBP)); + + ltdcp->active_window.hstart = hacc + 1; + ltdcp->active_window.vstart = vacc + 1; + + /* Set accumulated active params.*/ + osalDbgAssert(configp->screen_width >= LTDC_MIN_SCREEN_WIDTH, "bounds"); + osalDbgAssert(configp->screen_width <= LTDC_MAX_SCREEN_WIDTH, "bounds"); + osalDbgAssert(configp->screen_height >= LTDC_MIN_SCREEN_HEIGHT, "bounds"); + osalDbgAssert(configp->screen_height <= LTDC_MAX_SCREEN_HEIGHT, "bounds"); + + hacc += configp->screen_width; + vacc += configp->screen_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_ACTIVE_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_ACTIVE_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_ACTIVE_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_ACTIVE_HEIGHT, "bounds"); + + LTDC->AWCR = (((hacc << 16) & LTDC_AWCR_AAW) | + ((vacc << 0) & LTDC_AWCR_AAH)); + + ltdcp->active_window.hstop = hacc; + ltdcp->active_window.vstop = vacc; + + /* Set accumulated total params.*/ + osalDbgAssert(configp->hfp_width >= LTDC_MIN_HFP_WIDTH, "bounds"); + osalDbgAssert(configp->hfp_width <= LTDC_MAX_HFP_WIDTH, "bounds"); + osalDbgAssert(configp->vfp_height >= LTDC_MIN_VFP_HEIGHT, "bounds"); + osalDbgAssert(configp->vfp_height <= LTDC_MAX_VFP_HEIGHT, "bounds"); + + hacc += configp->hfp_width; + vacc += configp->vfp_height; + + osalDbgAssert(hacc + 1 >= LTDC_MIN_ACC_TOTAL_WIDTH, "bounds"); + osalDbgAssert(hacc + 1 <= LTDC_MAX_ACC_TOTAL_WIDTH, "bounds"); + osalDbgAssert(vacc + 1 >= LTDC_MIN_ACC_TOTAL_HEIGHT, "bounds"); + osalDbgAssert(vacc + 1 <= LTDC_MAX_ACC_TOTAL_HEIGHT, "bounds"); + + LTDC->TWCR = (((hacc << 16) & LTDC_TWCR_TOTALW) | + ((vacc << 0) & LTDC_TWCR_TOTALH)); + + /* Set signal polarities and other flags.*/ + ltdcSetEnableFlagsI(ltdcp, configp->flags & ~LTDC_EF_ENABLE); + + /* Color settings.*/ + ltdcSetClearColorI(ltdcp, configp->clear_color); + + /* Load layer configurations.*/ + ltdcBgSetConfigI(ltdcp, configp->bg_laycfg); + ltdcFgSetConfigI(ltdcp, configp->fg_laycfg); + + /* Enable only the assigned interrupt service routines.*/ + nvicEnableVector(STM32_LTDC_EV_NUMBER, STM32_LTDC_EV_IRQ_PRIORITY); + nvicEnableVector(STM32_LTDC_ER_NUMBER, STM32_LTDC_ER_IRQ_PRIORITY); + + flags = LTDC_IER_RRIE; + if (configp->line_isr != NULL) + flags |= LTDC_IER_LIE; + if (configp->fuerr_isr != NULL) + flags |= LTDC_IER_FUIE; + if (configp->terr_isr != NULL) + flags |= LTDC_IER_TERRIE; + LTDC->IER = flags; + + /* Apply settings.*/ + ltdc_force_reload_s(ltdcp); + + /* Turn on the controller.*/ + LTDC->GCR |= LTDC_GCR_LTDCEN; + ltdc_force_reload_s(ltdcp); + + ltdcp->state = LTDC_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the LTDC peripheral. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcStop(LTDCDriver *ltdcp) { + + osalDbgCheck(ltdcp == <DCD1); + + osalSysLock(); + osalDbgAssert(ltdcp->state == LTDC_READY, "invalid state"); + + /* Turn off the controller and its interrupts.*/ + LTDC->GCR &= ~LTDC_GCR_LTDCEN; + LTDC->IER = 0; +#if (TRUE == LTDC_USE_WAIT) + ltdcReloadS(ltdcp, true); +#else + ltdcStartReloadI(ltdcp, true); + while (ltdcIsReloadingI(ltdcp)) + chSchDoYieldS(); +#endif /* LTDC_USE_WAIT */ + + ltdcp->state = LTDC_STOP; + osalSysUnlock(); +} + +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) + +/** + * @brief Gains exclusive access to the LTDC module. + * @details This function tries to gain ownership to the LTDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + */ +void ltdcAcquireBusS(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxLockS(<dcp->lock); +#else + chSemWaitS(<dcp->lock); +#endif +} + +/** + * @brief Gains exclusive access to the LTDC module. + * @details This function tries to gain ownership to the LTDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcAcquireBus(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcAcquireBusS(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Releases exclusive access to the LTDC module. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @sclass + */ +void ltdcReleaseBusS(LTDCDriver *ltdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxUnlockS(<dcp->lock); +#else + chSemSignalI(<dcp->lock); +#endif +} + +/** + * @brief Releases exclusive access to the LTDC module. + * @pre In order to use this function the option + * @p LTDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcReleaseBus(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcReleaseBusS(ltdcp); + osalSysUnlock(); +} + +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ + +/** @} */ + +/** + * @name LTDC global methods + * @{ + */ + +/** + * @brief Get enabled flags. + * @details Returns all the flags of the <tt>LTDC_EF_*</tt> group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC->GCR & LTDC_EF_MASK; +} + +/** + * @brief Get enabled flags. + * @details Returns all the flags of the <tt>LTDC_EF_*</tt> group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set enabled flags. + * @details Sets all the flags of the <tt>LTDC_EF_*</tt> group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR = flags & LTDC_EF_MASK; +} + +/** + * @brief Set enabled flags. + * @details Sets all the flags of the <tt>LTDC_EF_*</tt> group at once. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Reloading shadow registers. + * @details Tells whether the LTDC is reloading shadow registers. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return reloading + * + * @iclass + */ +bool ltdcIsReloadingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->SRCR & (LTDC_SRCR_IMR | LTDC_SRCR_VBR)) != 0; +} + +/** + * @brief Reloading shadow registers. + * @details Tells whether the LTDC is reloading shadow registers. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return reloading + * + * @api + */ +bool ltdcIsReloading(LTDCDriver *ltdcp) { + + bool reloading; + osalSysLock(); + reloading = ltdcIsReloadingI(ltdcp); + osalSysUnlock(); + return reloading; +} + +/** + * @brief Reload shadow registers. + * @details Starts reloading LTDC shadow registers, upon vsync or immediately. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @iclass + */ +void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(ltdcp->state == LTDC_READY, "not ready"); + (void)ltdcp; + + ltdcp->state = LTDC_ACTIVE; + if (immediately) + LTDC->SRCR |= LTDC_SRCR_IMR; + else + LTDC->SRCR |= LTDC_SRCR_VBR; +} + +/** + * @brief Reload shadow registers. + * @details Starts reloading LTDC shadow registers, upon vsync or immediately. + * @post At the end of the operation the configured callback is invoked. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @api + */ +void ltdcStartReload(LTDCDriver *ltdcp, bool immediately) { + + osalSysLock(); + ltdcStartReloadI(ltdcp, immediately); + osalSysUnlock(); +} + +/** + * @brief Reload shadow registers. + * @details Reloads LTDC shadow registers, upon vsync or immediately. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @sclass + */ +void ltdcReloadS(LTDCDriver *ltdcp, bool immediately) { + + osalDbgCheckClassS(); + osalDbgCheck(ltdcp == <DCD1); + + ltdcStartReloadI(ltdcp, immediately); + +#if (TRUE == LTDC_USE_WAIT) + osalDbgAssert(ltdcp->thread == NULL, "already waiting"); + + if (immediately) { + while (LTDC->SRCR & LTDC_SRCR_IMR) + chSchDoYieldS(); + ltdcp->state = LTDC_READY; + } else { + ltdcp->thread = chThdGetSelfX(); + chSchGoSleepS(CH_STATE_SUSPENDED); + } +#else + while (LTDC->SRCR & LTDC_SRCR_IMR) + chSchDoYieldS(); + ltdcp->state = LTDC_READY; +#endif +} + +/** + * @brief Reload shadow registers. + * @details Reloads LTDC shadow registers, upon vsync or immediately. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] immediately reload immediately, not upon vsync + * + * @api + */ +void ltdcReload(LTDCDriver *ltdcp, bool immediately) { + + osalSysLock(); + ltdcReloadS(ltdcp, immediately); + osalSysUnlock(); +} + +/** + * @brief Dithering enabled. + * @details Tells whether the dithering is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->GCR & LTDC_GCR_DTEN) != 0; +} + +/** + * @brief Dithering enabled. + * @details Tells whether the dithering is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcIsDitheringEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable dithering. + * @details Enables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcEnableDitheringI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR |= LTDC_GCR_DTEN; +} + +/** + * @brief Enable dithering. + * @details Enables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcEnableDithering(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcEnableDitheringI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable dithering. + * @details Disables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcDisableDitheringI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->GCR &= ~LTDC_GCR_DTEN; +} + +/** + * @brief Disable dithering. + * @details Disables dithering capabilities for pixel formats with less than + * 8 bits per channel. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcDisableDithering(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcDisableDitheringI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get clear screen color. + * @details Gets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return clear screen color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC->BCCR & 0x00FFFFFF); +} + +/** + * @brief Get clear screen color. + * @details Gets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return clear screen color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcGetClearColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set clear screen color. + * @details Sets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c clear screen color, RGB-888 + * + * @iclass + */ +void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->BCCR = (LTDC->BCCR & ~0x00FFFFFF) | (c & 0x00FFFFFF); +} + +/** + * @brief Set clear screen color. + * @details Sets the clear screen (actual background) color. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c clear screen color, RGB-888 + * + * @api + */ +void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcSetClearColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get line interrupt position. + * @details Gets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return line interrupt position + * + * @iclass + */ +uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint16_t)(LTDC->LIPCR & LTDC_LIPCR_LIPOS); +} + +/** + * @brief Get line interrupt position. + * @details Gets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return line interrupt position + * + * @api + */ +uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp) { + + uint16_t line; + osalSysLock(); + line = ltdcGetLineInterruptPosI(ltdcp); + osalSysUnlock(); + return line; +} + +/** + * @brief Set line interrupt position. + * @details Sets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->LIPCR = ((LTDC->LIPCR & ~LTDC_LIPCR_LIPOS) | + ((uint32_t)line & LTDC_LIPCR_LIPOS)); +} + +/** + * @brief Set line interrupt position. + * @details Sets the line interrupt position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line) { + + osalSysLock(); + ltdcSetLineInterruptPosI(ltdcp, line); + osalSysUnlock(); +} + +/** + * @brief Line interrupt enabled. + * @details Tells whether the line interrupt is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC->IER & LTDC_IER_LIE) != 0; +} + +/** + * @brief Line interrupt enabled. + * @details Tells whether the line interrupt is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcIsLineInterruptEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable line interrupt. + * @details Enables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcEnableLineInterruptI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->IER |= LTDC_IER_LIE; +} + +/** + * @brief Enable line interrupt. + * @details Enables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcEnableLineInterrupt(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcEnableLineInterruptI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable line interrupt. + * @details Disables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcDisableLineInterruptI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC->IER &= ~LTDC_IER_LIE; +} + +/** + * @brief Disable line interrupt. + * @details Disables line interrupt. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcDisableLineInterrupt(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcDisableLineInterruptI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get current position. + * @details Gets the current position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] xp pointer to the destination horizontal coordinate + * @param[out] yp pointer to the destination vertical coordinate + * + * @iclass + */ +void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { + + const uint32_t r = LTDC->CPSR; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + *xp = (uint16_t)((r & LTDC_CPSR_CXPOS) >> 16); + *yp = (uint16_t)((r & LTDC_CPSR_CYPOS) >> 0); +} + +/** + * @brief Get current position. + * @details Gets the current position. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] xp pointer to the destination horizontal coordinate + * @param[out] yp pointer to the destination vertical coordinate + * + * @api + */ +void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp) { + + osalSysLock(); + ltdcGetCurrentPosI(ltdcp, xp, yp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC background layer (layer 1) methods + * @{ + */ + +/** + * @brief Get background layer enabled flags. + * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC_Layer1->CR & LTDC_LEF_MASK; +} + +/** + * @brief Get background layer enabled flags. + * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcBgGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set background layer enabled flags. + * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR = ((LTDC_Layer1->CR & ~LTDC_LEF_MASK) | + ((uint32_t)flags & LTDC_LEF_MASK)); +} + +/** + * @brief Set background layer enabled flags. + * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcBgSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Background layer enabled. + * @details Tells whether the background layer (layer 1) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_LEN) != 0; +} + +/** + * @brief Background layer enabled. + * @details Tells whether the background layer (layer 1) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Background layer enable. + * @details Enables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_LEN; +} + +/** + * @brief Background layer enable. + * @details Enables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Background layer disable. + * @details Disables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_LEN; +} + +/** + * @brief Background layer disable. + * @details Disables the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Background layer palette enabled. + * @details Tells whether the background layer (layer 1) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_CLUTEN) != 0; +} + +/** + * @brief Background layer palette enabled. + * @details Tells whether the background layer (layer 1) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsPaletteEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable background layer palette. + * @details Enables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_CLUTEN; +} + +/** + * @brief Enable background layer palette. + * @details Enables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable background layer palette. + * @details Disables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_CLUTEN; +} + +/** + * @brief Disable background layer palette. + * @details Disables the palette (color lookup table) of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Set background layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * background layer (layer 1). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @iclass + */ +void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + LTDC_Layer1->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); +} + +/** + * @brief Set background layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * background layer (layer 1). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @api + */ +void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetPaletteColorI(ltdcp, slot, c); + osalSysUnlock(); +} + +/** + * @brief Set background layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @iclass + */ +void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + uint16_t i; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck((colors == NULL) == (length == 0)); + osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(!ltdcBgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + for (i = 0; i < length; ++i) + LTDC_Layer1->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); +} + +/** + * @brief Set background layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @api + */ +void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + osalSysLock(); + ltdcBgSetPaletteI(ltdcp, colors, length); + osalSysUnlock(); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @iclass + */ +ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_pixfmt_t)(LTDC_Layer1->PFCR & LTDC_LxPFCR_PF); +} + +/** + * @brief Get background layer pixel format. + * @details Gets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @api + */ +ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp) { + + ltdc_pixfmt_t fmt; + osalSysLock(); + fmt = ltdcBgGetPixelFormatI(ltdcp); + osalSysUnlock(); + return fmt; +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); + osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); + (void)ltdcp; + + LTDC_Layer1->PFCR = ((LTDC_Layer1->PFCR & ~LTDC_LxPFCR_PF) | + ((uint32_t)fmt & LTDC_LxPFCR_PF)); +} + +/** + * @brief Set background layer pixel format. + * @details Sets the pixel format of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @api + */ +void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalSysLock(); + ltdcBgSetPixelFormatI(ltdcp, fmt); + osalSysUnlock(); +} + +/** + * @brief Background layer color keying enabled. + * @details Tells whether the background layer (layer 1) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer1->CR & ~LTDC_LxCR_COLKEN) != 0; +} + +/** + * @brief Background layer color keying enabled. + * @details Tells whether the background layer (layer 1) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcBgIsKeyingEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable background layer color keying. + * @details Enables color keying capabilities of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgEnableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR |= LTDC_LxCR_COLKEN; +} + +/** + * @brief Enable background layer color keying. + * @details Enables color keying capabilities of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgEnableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgEnableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable background layer color keying. + * @details Disables color keying capabilities of the background layer (layer + * 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgDisableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CR &= ~LTDC_LxCR_COLKEN; +} + +/** + * @brief Disable background layer color keying. + * @details Disables color keying capabilities of the background layer (layer + * 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgDisableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgDisableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get background layer color key. + * @details Gets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC_Layer1->CKCR & 0x00FFFFFF); +} + +/** + * @brief Get background layer color key. + * @details Gets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @api + */ +ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcBgGetKeyingColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set background layer color key. + * @details Sets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @iclass + */ +void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CKCR = ((LTDC_Layer1->CKCR & ~0x00FFFFFF) | + ((uint32_t)c & 0x00FFFFFF)); +} + +/** + * @brief Set background layer color key. + * @details Sets the color key of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @api + */ +void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetKeyingColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint8_t)(LTDC_Layer1->CACR & LTDC_LxCACR_CONSTA); +} + +/** + * @brief Get background layer constant alpha. + * @details Gets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp) { + + uint8_t a; + osalSysLock(); + a = ltdcBgGetConstantAlphaI(ltdcp); + osalSysUnlock(); + return a; +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CACR = ((LTDC_Layer1->CACR & ~LTDC_LxCACR_CONSTA) | + ((uint32_t)a & LTDC_LxCACR_CONSTA)); +} + +/** + * @brief Set background layer constant alpha. + * @details Sets the constant alpha component of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { + + osalSysLock(); + ltdcBgSetConstantAlphaI(ltdcp, a); + osalSysUnlock(); +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)LTDC_Layer1->DCCR; +} + +/** + * @brief Get background layer default color. + * @details Gets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcBgGetDefaultColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->DCCR = (uint32_t)c; +} + +/** + * @brief Set background layer default color. + * @details Sets the default color of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcBgSetDefaultColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get background layer blending factors. + * @details Gets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @iclass + */ +ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_blendf_t)(LTDC_Layer1->BFCR & LTDC_LxBFCR_BF); +} + +/** + * @brief Get background layer blending factors. + * @details Gets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @api + */ +ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp) { + + ltdc_blendf_t bf; + osalSysLock(); + bf = ltdcBgGetBlendingFactorsI(ltdcp); + osalSysUnlock(); + return bf; +} + +/** + * @brief Set background layer blending factors. + * @details Sets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @iclass + */ +void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->BFCR = ((LTDC_Layer1->BFCR & ~LTDC_LxBFCR_BF) | + ((uint32_t)bf & LTDC_LxBFCR_BF)); +} + +/** + * @brief Set background layer blending factors. + * @details Sets the blending factors of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @api + */ +void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalSysLock(); + ltdcBgSetBlendingFactorsI(ltdcp, bf); + osalSysUnlock(); +} + +/** + * @brief Get background layer window specs. + * @details Gets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + windowp->hstart = + (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); + windowp->hstop = + (uint16_t)((LTDC_Layer1->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); + windowp->vstart = + (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); + windowp->vstop = + (uint16_t)((LTDC_Layer1->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); +} + +/** + * @brief Get background layer window specs. + * @details Gets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @api + */ +void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalSysLock(); + ltdcBgGetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set background layer window specs. + * @details Sets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + uint32_t start, stop; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); + osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); + + /* Horizontal boundaries.*/ + start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; + stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; + + osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); + + LTDC_Layer1->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | + ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); + + /* Vertical boundaries.*/ + start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; + stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; + + osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); + + LTDC_Layer1->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | + ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); +} + +/** + * @brief Set background layer window specs. + * @details Sets the window specifications of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @api + */ +void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + osalSysLock(); + ltdcBgSetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set background layer window as invalid. + * @details Sets the window specifications of the background layer (layer 1) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp) { + + ltdcBgSetWindowI(ltdcp, <dc_invalid_window); +} + +/** + * @brief Set background layer window as invalid. + * @details Sets the window specifications of the background layer (layer 1) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcBgSetWindowI(ltdcp, <dc_invalid_window); + osalSysUnlock(); +} + +/** + * @brief Get background layer frame buffer specs. + * @details Gets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + framep->bufferp = (void *)(LTDC_Layer1->CFBAR & LTDC_LxCFBAR_CFBADD); + framep->pitch = (size_t)((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); + framep->width = (uint16_t)(((LTDC_Layer1->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / + ltdcBytesPerPixel(ltdcBgGetPixelFormatI(ltdcp))); + framep->height = (uint16_t)(LTDC_Layer1->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); +} + +/** + * @brief Get background layer frame buffer specs. + * @details Gets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalSysLock(); + ltdcBgGetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Set background layer frame buffer specs. + * @details Sets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + size_t linesize; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + ltdcBgSetPixelFormatI(ltdcp, framep->fmt); + + linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; + + osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); + osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); + osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->pitch >= linesize, "bounds"); + + LTDC_Layer1->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; + LTDC_Layer1->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | + ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); + LTDC_Layer1->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; +} + +/** + * @brief Set background layer frame buffer specs. + * @details Sets the frame buffer specifications of the background layer + * (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + osalSysLock(); + ltdcBgSetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Get background layer frame buffer address. + * @details Gets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @iclass + */ +void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (void *)LTDC_Layer1->CFBAR; +} + +/** + * @brief Get background layer frame buffer address. + * @details Gets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @api + */ +void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp) { + + void *bufferp; + osalSysLock(); + bufferp = ltdcBgGetFrameAddressI(ltdcp); + osalSysUnlock(); + return bufferp; +} + +/** + * @brief Set background layer frame buffer address. + * @details Sets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @iclass + */ +void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer1->CFBAR = (uint32_t)bufferp; +} + +/** + * @brief Set background layer frame buffer address. + * @details Sets the frame buffer address of the background layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @api + */ +void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { + + osalSysLock(); + ltdcBgSetFrameAddressI(ltdcp, bufferp); + osalSysUnlock(); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer (layer 1) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(cfgp != NULL); + + ltdcBgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); + ltdcBgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); + cfgp->def_color = ltdcBgGetDefaultColorI(ltdcp); + cfgp->key_color = ltdcBgGetKeyingColorI(ltdcp); + cfgp->const_alpha = ltdcBgGetConstantAlphaI(ltdcp); + cfgp->blending = ltdcBgGetBlendingFactorsI(ltdcp); + + cfgp->pal_colors = NULL; + cfgp->pal_length = 0; + + cfgp->flags = ltdcBgGetEnableFlagsI(ltdcp); +} + +/** + * @brief Get background layer specifications. + * @details Gets the background layer (layer 1) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcBgGetLayerI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer (layer 1) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + if (cfgp == NULL) + cfgp = <dc_default_laycfg; + + osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); + + ltdcBgSetFrameI(ltdcp, cfgp->frame); + ltdcBgSetWindowI(ltdcp, cfgp->window); + ltdcBgSetDefaultColorI(ltdcp, cfgp->def_color); + ltdcBgSetKeyingColorI(ltdcp, cfgp->key_color); + ltdcBgSetConstantAlphaI(ltdcp, cfgp->const_alpha); + ltdcBgSetBlendingFactorsI(ltdcp, cfgp->blending); + + if (cfgp->pal_length > 0) + ltdcBgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); + + ltdcBgSetEnableFlagsI(ltdcp, cfgp->flags); +} + +/** + * @brief Set background layer specifications. + * @details Sets the background layer (layer 1) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcBgSetConfigI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC foreground layer (layer 2) methods + * @{ + */ + +/** + * @brief Get foreground layer enabled flags. + * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @iclass + */ +ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return LTDC_Layer2->CR & LTDC_LEF_MASK; +} + +/** + * @brief Get foreground layer enabled flags. + * @details Returns all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled flags + * + * @api + */ +ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp) { + + ltdc_flags_t flags; + osalSysLock(); + flags = ltdcFgGetEnableFlagsI(ltdcp); + osalSysUnlock(); + return flags; +} + +/** + * @brief Set foreground layer enabled flags. + * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @iclass + */ +void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR = ((LTDC_Layer2->CR & ~LTDC_LEF_MASK) | + ((uint32_t)flags & LTDC_LEF_MASK)); +} + +/** + * @brief Set foreground layer enabled flags. + * @details Sets all the flags of the <tt>LTDC_LEF_*</tt> group at once. + * Targeting the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] flags enabled flags + * + * @api + */ +void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags) { + + osalSysLock(); + ltdcFgSetEnableFlagsI(ltdcp, flags); + osalSysUnlock(); +} + +/** + * @brief Foreground layer enabled. + * @details Tells whether the foreground layer (layer 2) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_LEN) != 0; +} + +/** + * @brief Foreground layer enabled. + * @details Tells whether the foreground layer (layer 2) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Foreground layer enable. + * @details Enables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_LEN; +} + +/** + * @brief Foreground layer enable. + * @details Enables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Foreground layer disable. + * @details Disables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisableI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_LEN; +} + +/** + * @brief Foreground layer disable. + * @details Disables the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisable(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisableI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Foreground layer palette enabled. + * @details Tells whether the foreground layer (layer 2) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_CLUTEN) != 0; +} + +/** + * @brief Foreground layer palette enabled. + * @details Tells whether the foreground layer (layer 2) palette (color lookup + * table) is enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsPaletteEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable foreground layer palette. + * @details Enables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_CLUTEN; +} + +/** + * @brief Enable foreground layer palette. + * @details Enables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable foreground layer palette. + * @details Disables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisablePaletteI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_CLUTEN; +} + +/** + * @brief Disable foreground layer palette. + * @details Disables the palette (color lookup table) of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisablePalette(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisablePaletteI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * foreground layer (layer 2). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @iclass + */ +void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + LTDC_Layer2->CLUTWR = (((uint32_t)slot << 24) | (c & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer palette color. + * @details Sets the color of a palette (color lookup table) slot to the + * foreground layer (layer 2). + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] slot palette slot + * @param[in] c color, RGB-888 + * + * @api + */ +void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetPaletteColorI(ltdcp, slot, c); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @iclass + */ +void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + uint16_t i; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck((colors == NULL) == (length == 0)); + osalDbgAssert(length <= LTDC_MAX_PALETTE_LENGTH, "bounds"); + osalDbgAssert(!ltdcFgIsEnabledI(ltdcp), "invalid state"); + (void)ltdcp; + + for (i = 0; i < length; ++i) + LTDC_Layer2->CLUTWR = (((uint32_t)i << 24) | (colors[i] & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer palette. + * @details Sets the entire palette color (color lookup table) slot. + * @pre The layer must be disabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] colors array of palette colors, RGB-888 + * @param[in] length number of palette colors + * + * @api + */ +void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length) { + + osalSysLock(); + ltdcFgSetPaletteI(ltdcp, colors, length); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @iclass + */ +ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_pixfmt_t)(LTDC_Layer2->PFCR & LTDC_LxPFCR_PF); +} + +/** + * @brief Get foreground layer pixel format. + * @details Gets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return pixel format + * + * @api + */ +ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp) { + + ltdc_pixfmt_t fmt; + osalSysLock(); + fmt = ltdcFgGetPixelFormatI(ltdcp); + osalSysUnlock(); + return fmt; +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @iclass + */ +void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgAssert(fmt >= LTDC_MIN_PIXFMT_ID, "bounds"); + osalDbgAssert(fmt <= LTDC_MAX_PIXFMT_ID, "bounds"); + (void)ltdcp; + + LTDC_Layer2->PFCR = ((LTDC_Layer2->PFCR & ~LTDC_LxPFCR_PF) | + ((uint32_t)fmt & LTDC_LxPFCR_PF)); +} + +/** + * @brief Set foreground layer pixel format. + * @details Sets the pixel format of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] fmt pixel format + * + * @api + */ +void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt) { + + osalSysLock(); + ltdcFgSetPixelFormatI(ltdcp, fmt); + osalSysUnlock(); +} + +/** + * @brief Foreground layer color keying enabled. + * @details Tells whether the foreground layer (layer 2) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @iclass + */ +bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (LTDC_Layer2->CR & ~LTDC_LxCR_COLKEN) != 0; +} + +/** + * @brief Foreground layer color keying enabled. + * @details Tells whether the foreground layer (layer 2) has color keying + * enabled. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return enabled + * + * @api + */ +bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp) { + + bool enabled; + osalSysLock(); + enabled = ltdcFgIsKeyingEnabledI(ltdcp); + osalSysUnlock(); + return enabled; +} + +/** + * @brief Enable foreground layer color keying. + * @details Enables color keying capabilities of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgEnableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR |= LTDC_LxCR_COLKEN; +} + +/** + * @brief Enable foreground layer color keying. + * @details Enables color keying capabilities of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgEnableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgEnableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Disable foreground layer color keying. + * @details Disables color keying capabilities of the foreground layer (layer + * 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgDisableKeyingI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CR &= ~LTDC_LxCR_COLKEN; +} + +/** + * @brief Disable foreground layer color keying. + * @details Disables color keying capabilities of the foreground layer (layer + * 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgDisableKeying(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgDisableKeyingI(ltdcp); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer color key. + * @details Gets the color key of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)(LTDC_Layer2->CKCR & 0x00FFFFFF); +} + +/** + * @brief Get foreground layer color key. + * @details Gets the color key of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return color key, RGB-888 + * + * @api + */ +ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcFgGetKeyingColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set foreground layer color key. + * @details Sets the color key of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @iclass + */ +void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CKCR = ((LTDC_Layer2->CKCR & ~0x00FFFFFF) | + ((uint32_t)c & 0x00FFFFFF)); +} + +/** + * @brief Set foreground layer color key. + * @details Sets the color key of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c color key, RGB-888 + * + * @api + */ +void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetKeyingColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @iclass + */ +uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (uint8_t)(LTDC_Layer2->CACR & LTDC_LxCACR_CONSTA); +} + +/** + * @brief Get foreground layer constant alpha. + * @details Gets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return constant alpha component, A-8 + * + * @api + */ +uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp) { + + uint8_t a; + osalSysLock(); + a = ltdcFgGetConstantAlphaI(ltdcp); + osalSysUnlock(); + return a; +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @iclass + */ +void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CACR = ((LTDC_Layer2->CACR & ~LTDC_LxCACR_CONSTA) | + ((uint32_t)a & LTDC_LxCACR_CONSTA)); +} + +/** + * @brief Set foreground layer constant alpha. + * @details Sets the constant alpha component of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] a constant alpha component, A-8 + * + * @api + */ +void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a) { + + osalSysLock(); + ltdcFgSetConstantAlphaI(ltdcp, a); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @iclass + */ +ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_color_t)LTDC_Layer2->DCCR; +} + +/** + * @brief Get foreground layer default color. + * @details Gets the default color of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return default color, RGB-888 + * + * @api + */ +ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp) { + + ltdc_color_t color; + osalSysLock(); + color = ltdcFgGetDefaultColorI(ltdcp); + osalSysUnlock(); + return color; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @iclass + */ +void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->DCCR = (uint32_t)c; +} + +/** + * @brief Set foreground layer default color. + * @details Sets the default color of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] c default color, RGB-888 + * + * @api + */ +void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c) { + + osalSysLock(); + ltdcFgSetDefaultColorI(ltdcp, c); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer blending factors. + * @details Gets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @iclass + */ +ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (ltdc_blendf_t)(LTDC_Layer2->BFCR & LTDC_LxBFCR_BF); +} + +/** + * @brief Get foreground layer blending factors. + * @details Gets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return blending factors + * + * @api + */ +ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp) { + + ltdc_blendf_t bf; + osalSysLock(); + bf = ltdcFgGetBlendingFactorsI(ltdcp); + osalSysUnlock(); + return bf; +} + +/** + * @brief Set foreground layer blending factors. + * @details Sets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @iclass + */ +void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->BFCR = ((LTDC_Layer2->BFCR & ~LTDC_LxBFCR_BF) | + ((uint32_t)bf & LTDC_LxBFCR_BF)); +} + +/** + * @brief Set foreground layer blending factors. + * @details Sets the blending factors of the foreground layer (layer 1). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] factors blending factors + * + * @api + */ +void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf) { + + osalSysLock(); + ltdcFgSetBlendingFactorsI(ltdcp, bf); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer window specs. + * @details Gets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + windowp->hstart = + (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSTPOS) >> 0); + windowp->hstop = + (uint16_t)((LTDC_Layer2->WHPCR & LTDC_LxWHPCR_WHSPPOS) >> 16); + windowp->vstart = + (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSTPOS) >> 0); + windowp->vstop = + (uint16_t)((LTDC_Layer2->WVPCR & LTDC_LxWVPCR_WVSPPOS) >> 16); +} + +/** + * @brief Get foreground layer window specs. + * @details Gets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] windowp pointer to the window specifications + * + * @api + */ +void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp) { + + osalSysLock(); + ltdcFgGetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer window specs. + * @details Sets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @iclass + */ +void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + uint32_t start, stop; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(windowp != NULL); + (void)ltdcp; + + osalDbgAssert(windowp->hstop < ltdcp->config->screen_width, "bounds"); + osalDbgAssert(windowp->vstop < ltdcp->config->screen_height, "bounds"); + + /* Horizontal boundaries.*/ + start = (uint32_t)windowp->hstart + ltdcp->active_window.hstart; + stop = (uint32_t)windowp->hstop + ltdcp->active_window.hstart; + + osalDbgAssert(start >= ltdcp->active_window.hstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.hstop, "bounds"); + + LTDC_Layer2->WHPCR = (((start << 0) & LTDC_LxWHPCR_WHSTPOS) | + ((stop << 16) & LTDC_LxWHPCR_WHSPPOS)); + + /* Vertical boundaries.*/ + start = (uint32_t)windowp->vstart + ltdcp->active_window.vstart; + stop = (uint32_t)windowp->vstop + ltdcp->active_window.vstart; + + osalDbgAssert(start >= ltdcp->active_window.vstart, "bounds"); + osalDbgAssert(stop <= ltdcp->active_window.vstop, "bounds"); + + LTDC_Layer2->WVPCR = (((start << 0) & LTDC_LxWVPCR_WVSTPOS) | + ((stop << 16) & LTDC_LxWVPCR_WVSPPOS)); +} + +/** + * @brief Set foreground layer window specs. + * @details Sets the window specifications of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] windowp pointer to the window specifications + * + * @api + */ +void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp) { + + osalSysLock(); + ltdcFgSetWindowI(ltdcp, windowp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer window as invalid. + * @details Sets the window specifications of the foreground layer (layer 2) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @iclass + */ +void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp) { + + ltdcFgSetWindowI(ltdcp, <dc_invalid_window); +} + +/** + * @brief Set foreground layer window as invalid. + * @details Sets the window specifications of the foreground layer (layer 2) + * so that the window is pixel sized at the screen origin. + * @note Useful before reconfiguring the frame specifications of the layer, + * to avoid errors. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @api + */ +void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp) { + + osalSysLock(); + ltdcFgSetWindowI(ltdcp, <dc_invalid_window); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer frame buffer specs. + * @details Gets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + framep->bufferp = (void *)(LTDC_Layer2->CFBAR & LTDC_LxCFBAR_CFBADD); + framep->pitch = (size_t)((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBP) >> 16); + framep->width = (uint16_t)(((LTDC_Layer2->CFBLR & LTDC_LxCFBLR_CFBLL) - 3) / + ltdcBytesPerPixel(ltdcFgGetPixelFormatI(ltdcp))); + framep->height = (uint16_t)(LTDC_Layer2->CFBLNR & LTDC_LxCFBLNR_CFBLNBR); +} + +/** + * @brief Get foreground layer frame buffer specs. + * @details Gets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep) { + + osalSysLock(); + ltdcFgGetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer frame buffer specs. + * @details Sets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @iclass + */ +void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + size_t linesize; + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(framep != NULL); + + ltdcFgSetPixelFormatI(ltdcp, framep->fmt); + + linesize = ltdcBytesPerPixel(framep->fmt) * framep->width; + + osalDbgAssert(framep->width <= ltdcp->config->screen_width, "bounds"); + osalDbgAssert(framep->height <= ltdcp->config->screen_height, "bounds"); + osalDbgAssert(linesize >= LTDC_MIN_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(linesize <= LTDC_MAX_FRAME_WIDTH_BYTES, "bounds"); + osalDbgAssert(framep->height >= LTDC_MIN_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->height <= LTDC_MAX_FRAME_HEIGHT_LINES, "bounds"); + osalDbgAssert(framep->pitch >= linesize, "bounds"); + + LTDC_Layer2->CFBAR = (uint32_t)framep->bufferp & LTDC_LxCFBAR_CFBADD; + LTDC_Layer2->CFBLR = ((((uint32_t)framep->pitch << 16) & LTDC_LxCFBLR_CFBP) | + ((linesize + 3) & LTDC_LxCFBLR_CFBLL)); + LTDC_Layer2->CFBLNR = (uint32_t)framep->height & LTDC_LxCFBLNR_CFBLNBR; +} + +/** + * @brief Set foreground layer frame buffer specs. + * @details Sets the frame buffer specifications of the foreground layer + * (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] framep pointer to the frame buffer specifications + * + * @api + */ +void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep) { + + osalSysLock(); + ltdcFgSetFrameI(ltdcp, framep); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer frame buffer address. + * @details Gets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @iclass + */ +void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + return (void *)LTDC_Layer2->CFBAR; +} + +/** + * @brief Get foreground layer frame buffer address. + * @details Gets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * + * @return frame buffer address + * + * @api + */ +void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp) { + + void *bufferp; + osalSysLock(); + bufferp = ltdcFgGetFrameAddressI(ltdcp); + osalSysUnlock(); + return bufferp; +} + +/** + * @brief Set foreground layer frame buffer address. + * @details Sets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @iclass + */ +void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + (void)ltdcp; + + LTDC_Layer2->CFBAR = (uint32_t)bufferp; +} + +/** + * @brief Set foreground layer frame buffer address. + * @details Sets the frame buffer address of the foreground layer (layer 2). + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] bufferp frame buffer address + * + * @api + */ +void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp) { + + osalSysLock(); + ltdcFgSetFrameAddressI(ltdcp, bufferp); + osalSysUnlock(); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer (layer 2) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + osalDbgCheck(cfgp != NULL); + + ltdcFgGetFrameI(ltdcp, (ltdc_frame_t *)cfgp->frame); + ltdcFgGetWindowI(ltdcp, (ltdc_window_t *)cfgp->window); + cfgp->def_color = ltdcFgGetDefaultColorI(ltdcp); + cfgp->key_color = ltdcFgGetKeyingColorI(ltdcp); + cfgp->const_alpha = ltdcFgGetConstantAlphaI(ltdcp); + cfgp->blending = ltdcFgGetBlendingFactorsI(ltdcp); + + cfgp->pal_colors = NULL; + cfgp->pal_length = 0; + + cfgp->flags = ltdcFgGetEnableFlagsI(ltdcp); +} + +/** + * @brief Get foreground layer specifications. + * @details Gets the foreground layer (layer 2) specifications at once. + * @note If palette specifications cannot be retrieved, they are set to + * @p NULL. This is not an error. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[out] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcFgGetLayerI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer (layer 2) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @iclass + */ +void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalDbgCheckClassI(); + osalDbgCheck(ltdcp == <DCD1); + + if (cfgp == NULL) + cfgp = <dc_default_laycfg; + + osalDbgCheck((cfgp->pal_colors == NULL) == (cfgp->pal_length == 0)); + + ltdcFgSetFrameI(ltdcp, cfgp->frame); + ltdcFgSetWindowI(ltdcp, cfgp->window); + ltdcFgSetDefaultColorI(ltdcp, cfgp->def_color); + ltdcFgSetKeyingColorI(ltdcp, cfgp->key_color); + ltdcFgSetConstantAlphaI(ltdcp, cfgp->const_alpha); + ltdcFgSetBlendingFactorsI(ltdcp, cfgp->blending); + + if (cfgp->pal_length > 0) + ltdcFgSetPaletteI(ltdcp, cfgp->pal_colors, cfgp->pal_length); + + ltdcFgSetEnableFlagsI(ltdcp, cfgp->flags); +} + +/** + * @brief Set foreground layer specifications. + * @details Sets the foreground layer (layer 2) specifications at once. + * @note If the palette is unspecified, the layer palette is unmodified. + * + * @param[in] ltdcp pointer to the @p LTDCDriver object + * @param[in] cfgp pointer to the layer specifications + * + * @api + */ +void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp) { + + osalSysLock(); + ltdcFgSetConfigI(ltdcp, cfgp); + osalSysUnlock(); +} + +/** @} */ + +/** + * @name LTDC helper functions + */ + +/** + * @brief Compute bits per pixel. + * @details Computes the bits per pixel for the specified pixel format. + * + * @param[in] fmt pixel format + * + * @retuen bits per pixel + * + * @api + */ +size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt) { + + osalDbgAssert(fmt < LTDC_MAX_PIXFMT_ID, "invalid format"); + + return (size_t)ltdc_bpp[(unsigned)fmt]; +} + +#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + +/** + * @brief Convert from ARGB-8888. + * @details Converts an ARGB-8888 color to the specified pixel format. + * + * @param[in] c color, ARGB-8888 + * @param[in] fmt target pixel format + * + * @return raw color value for the target pixel format, left + * padded with zeros. + * + * @api + */ +ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { + + switch (fmt) { + case LTDC_FMT_ARGB8888: { + return c; + } + case LTDC_FMT_RGB888: { + return (c & 0x00FFFFFF); + } + case LTDC_FMT_RGB565: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000FC00) >> (16 - 11)) | + ((c & 0x00F80000) >> (24 - 16))); + } + case LTDC_FMT_ARGB1555: { + return (((c & 0x000000F8) >> ( 8 - 5)) | + ((c & 0x0000F800) >> (16 - 10)) | + ((c & 0x00F80000) >> (24 - 15)) | + ((c & 0x80000000) >> (32 - 16))); + } + case LTDC_FMT_ARGB4444: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0x0000F000) >> (16 - 8)) | + ((c & 0x00F00000) >> (24 - 12)) | + ((c & 0xF0000000) >> (32 - 16))); + } + case LTDC_FMT_L8: { + return (c & 0x000000FF); + } + case LTDC_FMT_AL44: { + return (((c & 0x000000F0) >> ( 8 - 4)) | + ((c & 0xF0000000) >> (32 - 8))); + } + case LTDC_FMT_AL88: { + return (((c & 0x000000FF) >> ( 8 - 8)) | + ((c & 0xFF000000) >> (32 - 16))); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +/** + * @brief Convert to ARGB-8888. + * @details Converts color of the specified pixel format to an ARGB-8888 color. + * + * @param[in] c color for the source pixel format, left padded with + * zeros. + * @param[in] fmt source pixel format + * + * @return color in ARGB-8888 format + * + * @api + */ +ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt) { + + switch (fmt) { + case LTDC_FMT_ARGB8888: { + return c; + } + case LTDC_FMT_RGB888: { + return ((c & 0x00FFFFFF) | 0xFF000000); + } + case LTDC_FMT_RGB565: { + register ltdc_color_t output = 0xFF000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x07E0) output |= (((c & 0x07E0) << (16 - 11)) | 0x00000300); + if (c & 0xF800) output |= (((c & 0xF800) << (24 - 16)) | 0x00070000); + return output; + } + case LTDC_FMT_ARGB1555: { + register ltdc_color_t output = 0x00000000; + if (c & 0x001F) output |= (((c & 0x001F) << ( 8 - 5)) | 0x00000007); + if (c & 0x03E0) output |= (((c & 0x03E0) << (16 - 10)) | 0x00000700); + if (c & 0x7C00) output |= (((c & 0x7C00) << (24 - 15)) | 0x00070000); + if (c & 0x8000) output |= 0xFF000000; + return output; + } + case LTDC_FMT_ARGB4444: { + register ltdc_color_t output = 0x00000000; + if (c & 0x000F) output |= (((c & 0x000F) << ( 8 - 4)) | 0x0000000F); + if (c & 0x00F0) output |= (((c & 0x00F0) << (16 - 8)) | 0x00000F00); + if (c & 0x0F00) output |= (((c & 0x0F00) << (24 - 12)) | 0x000F0000); + if (c & 0xF000) output |= (((c & 0xF000) << (32 - 16)) | 0x0F000000); + return output; + } + case LTDC_FMT_L8: { + return ((c & 0xFF) | 0xFF000000); + } + case LTDC_FMT_AL44: { + register ltdc_color_t output = 0x00000000; + if (c & 0x0F) output |= (((c & 0x0F) << ( 8 - 4)) | 0x0000000F); + if (c & 0xF0) output |= (((c & 0xF0) << (32 - 8)) | 0x0F000000); + return output; + } + case LTDC_FMT_AL88: { + return (((c & 0x00FF) << ( 8 - 8)) | + ((c & 0xFF00) << (32 - 16))); + } + default: + osalDbgAssert(false, "invalid format"); + return 0; + } +} + +#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ + +/** @} */ + +/** @} */ + +#endif /* STM32_LTDC_USE_LTDC */ diff --git a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h index fdf1f5b..16b38ca 100644 --- a/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.h +++ b/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.h @@ -1,736 +1,736 @@ -/*
- Copyright (C) 2013-2015 Andrea Zoppi
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file stm32_ltdc.h
- * @brief LCD-TFT Controller Driver.
- *
- * @addtogroup ltdc
- * @{
- */
-
-#ifndef _STM32_LTDC_H_
-#define _STM32_LTDC_H_
-
-/**
- * @brief Using the LTDC driver.
- */
-#if !defined(STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__)
-#define STM32_LTDC_USE_LTDC (FALSE)
-#endif
-
-#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver constants. */
-/*===========================================================================*/
-
-/**
- * @name LTDC enable flags
- * @{
- */
-#define LTDC_EF_ENABLE (1 << 0) /**< LTDC enabled.*/
-#define LTDC_EF_DITHER (1 << 16) /**< Dithering enabled.*/
-#define LTDC_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/
-#define LTDC_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/
-#define LTDC_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/
-#define LTDC_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/
-
-#define LTDC_EF_MASK \
- (LTDC_EF_ENABLE | LTDC_EF_DITHER | LTDC_EF_PIXCLK_INVERT | \
- LTDC_EF_DATAEN_HIGH | LTDC_EF_VSYNC_HIGH | LTDC_EF_HSYNC_HIGH)
-/** @} */
-
-/**
- * @name LTDC layer enable flags
- * @{
- */
-#define LTDC_LEF_ENABLE (1 << 0) /**< Layer enabled*/
-#define LTDC_LEF_KEYING (1 << 1) /**< Color keying enabled.*/
-#define LTDC_LEF_PALETTE (1 << 4) /**< Palette enabled.*/
-
-#define LTDC_LEF_MASK \
- (LTDC_LEF_ENABLE | LTDC_LEF_KEYING | LTDC_LEF_PALETTE)
-/** @} */
-
-/**
- * @name LTDC pixel formats
- * @{
- */
-#define LTDC_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/
-#define LTDC_FMT_RGB888 (1) /**< RGB-888 format.*/
-#define LTDC_FMT_RGB565 (2) /**< RGB-565 format.*/
-#define LTDC_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/
-#define LTDC_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/
-#define LTDC_FMT_L8 (5) /**< L-8 format.*/
-#define LTDC_FMT_AL44 (6) /**< AL-44 format.*/
-#define LTDC_FMT_AL88 (7) /**< AL-88 format.*/
-/** @} */
-
-/**
- * @name LTDC pixel format aliased raw masks
- * @{
- */
-#define LTDC_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/
-#define LTDC_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/
-#define LTDC_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/
-#define LTDC_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/
-#define LTDC_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/
-#define LTDC_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/
-#define LTDC_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/
-#define LTDC_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/
-/** @} */
-
-/**
- * @name LTDC blending factors
- * @{
- */
-#define LTDC_BLEND_FIX1_FIX2 (0x0405) /**< cnst1; 1 - cnst2 */
-#define LTDC_BLEND_FIX1_MOD2 (0x0407) /**< cnst1; 1 - a2 * cnst2 */
-#define LTDC_BLEND_MOD1_FIX2 (0x0605) /**< a1 * cnst1; 1 - cnst2 */
-#define LTDC_BLEND_MOD1_MOD2 (0x0607) /**< a1 * cnst1; 1 - a2 * cnst2 */
-/** @} */
-
-/**
- * @name LTDC parameter bounds
- * @{
- */
-
-#define LTDC_MIN_SCREEN_WIDTH (1)
-#define LTDC_MIN_SCREEN_HEIGHT (1)
-#define LTDC_MAX_SCREEN_WIDTH (800)
-#define LTDC_MAX_SCREEN_HEIGHT (600)
-
-#define LTDC_MIN_HSYNC_WIDTH (1)
-#define LTDC_MIN_VSYNC_HEIGHT (1)
-#define LTDC_MAX_HSYNC_WIDTH (1 << 12)
-#define LTDC_MAX_VSYNC_HEIGHT (1 << 11)
-
-#define LTDC_MIN_HBP_WIDTH (0)
-#define LTDC_MIN_VBP_HEIGHT (0)
-#define LTDC_MAX_HBP_WIDTH (1 << 12)
-#define LTDC_MAX_VBP_HEIGHT (1 << 11)
-
-#define LTDC_MIN_ACC_HBP_WIDTH (1)
-#define LTDC_MIN_ACC_VBP_HEIGHT (1)
-#define LTDC_MAX_ACC_HBP_WIDTH (1 << 12)
-#define LTDC_MAX_ACC_VBP_HEIGHT (1 << 11)
-
-#define LTDC_MIN_HFP_WIDTH (0)
-#define LTDC_MIN_VFP_HEIGHT (0)
-#define LTDC_MAX_HFP_WIDTH (1 << 12)
-#define LTDC_MAX_VFP_HEIGHT (1 << 11)
-
-#define LTDC_MIN_ACTIVE_WIDTH (0)
-#define LTDC_MIN_ACTIVE_HEIGHT (0)
-#define LTDC_MAX_ACTIVE_WIDTH (1 << 12)
-#define LTDC_MAX_ACTIVE_HEIGHT (1 << 11)
-
-#define LTDC_MIN_ACC_ACTIVE_WIDTH (1)
-#define LTDC_MIN_ACC_ACTIVE_HEIGHT (1)
-#define LTDC_MAX_ACC_ACTIVE_WIDTH (1 << 12)
-#define LTDC_MAX_ACC_ACTIVE_HEIGHT (1 << 11)
-
-#define LTDC_MIN_ACC_TOTAL_WIDTH (1)
-#define LTDC_MIN_ACC_TOTAL_HEIGHT (1)
-#define LTDC_MAX_ACC_TOTAL_WIDTH (1 << 12)
-#define LTDC_MAX_ACC_TOTAL_HEIGHT (1 << 11)
-
-#define LTDC_MIN_LINE_INTERRUPT_POS (0)
-#define LTDC_MAX_LINE_INTERRUPT_POS ((1 << 11) - 1)
-
-#define LTDC_MIN_WINDOW_HSTART (0)
-#define LTDC_MIN_WINDOW_HSTART (0)
-#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1)
-#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1)
-
-#define LTDC_MIN_WINDOW_VSTART (0)
-#define LTDC_MIN_WINDOW_VSTART (0)
-#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1)
-#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1)
-
-#define LTDC_MIN_FRAME_WIDTH_BYTES (0)
-#define LTDC_MIN_FRAME_HEIGHT_LINES (0)
-#define LTDC_MIN_FRAME_PITCH_BYTES (0)
-#define LTDC_MAX_FRAME_WIDTH_BYTES ((1 << 13) - 1 - 3)
-#define LTDC_MAX_FRAME_HEIGHT_LINES ((1 << 11) - 1)
-#define LTDC_MAX_FRAME_PITCH_BYTES ((1 << 13) - 1)
-
-#define LTDC_MIN_PIXFMT_ID (0)
-#define LTDC_MAX_PIXFMT_ID (7)
-
-#define LTDC_MAX_PALETTE_LENGTH (256)
-
-/** @} */
-
-/**
- * @name LTDC basic ARGB-8888 colors.
- * @{
- */
-/* Microsoft Windows default 16-color palette.*/
-#define LTDC_COLOR_BLACK (0xFF000000)
-#define LTDC_COLOR_MAROON (0xFF800000)
-#define LTDC_COLOR_GREEN (0xFF008000)
-#define LTDC_COLOR_OLIVE (0xFF808000)
-#define LTDC_COLOR_NAVY (0xFF000080)
-#define LTDC_COLOR_PURPLE (0xFF800080)
-#define LTDC_COLOR_TEAL (0xFF008080)
-#define LTDC_COLOR_SILVER (0xFFC0C0C0)
-#define LTDC_COLOR_GRAY (0xFF808080)
-#define LTDC_COLOR_RED (0xFFFF0000)
-#define LTDC_COLOR_LIME (0xFF00FF00)
-#define LTDC_COLOR_YELLOW (0xFFFFFF00)
-#define LTDC_COLOR_BLUE (0xFF0000FF)
-#define LTDC_COLOR_FUCHSIA (0xFFFF00FF)
-#define LTDC_COLOR_AQUA (0xFF00FFFF)
-#define LTDC_COLOR_WHITE (0xFFFFFFFF)
-/** @} */
-
-/*===========================================================================*/
-/* Driver pre-compile time settings. */
-/*===========================================================================*/
-
-/**
- * @name LTDC configuration options
- * @{
- */
-
-/**
- * @brief LTDC event interrupt priority level setting.
- */
-#if !defined(STM32_LTDC_EV_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_LTDC_EV_IRQ_PRIORITY (11)
-#endif
-
-/**
- * @brief LTDC error interrupt priority level setting.
- */
-#if !defined(STM32_LTDC_ER_IRQ_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_LTDC_ER_IRQ_PRIORITY (11)
-#endif
-
-/**
- * @brief Enables synchronous APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(LTDC_USE_WAIT) || defined(__DOXYGEN__)
-#define LTDC_USE_WAIT (TRUE)
-#endif
-
-/**
- * @brief Enables the @p ltdcAcquireBus() and @p ltdcReleaseBus() APIs.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(LTDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
-#define LTDC_USE_MUTUAL_EXCLUSION (TRUE)
-#endif
-
-/**
- * @brief Provides software color conversion functions.
- * @note Disabling this option saves both code and data space.
- */
-#if !defined(LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__)
-#define LTDC_USE_SOFTWARE_CONVERSIONS (TRUE)
-#endif
-
-/**
- * @brief Enables checks for LTDC functions.
- * @note Disabling this option saves both code and data space.
- * @note Disabling checks by ChibiOS will automatically disable LTDC checks.
- */
-#if !defined(LTDC_USE_CHECKS) || defined(__DOXYGEN__)
-#define LTDC_USE_CHECKS (TRUE)
-#endif
-
-/** @} */
-
-/*===========================================================================*/
-/* Derived constants and error checks. */
-/*===========================================================================*/
-
-#if (TRUE != STM32_HAS_LTDC)
-#error "LTDC must be present when using the LTDC subsystem"
-#endif
-
-#if (TRUE == STM32_LTDC_USE_LTDC) && (TRUE != STM32_HAS_LTDC)
-#error "LTDC not present in the selected device"
-#endif
-
-#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION)
-#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES)
-#error "LTDC_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES"
-#endif
-#endif
-
-/*===========================================================================*/
-/* Driver data structures and types. */
-/*===========================================================================*/
-
-/* Complex types forwarding.*/
-typedef union ltdc_coloralias_t ltdc_coloralias_t;
-typedef struct ltdc_window_t ltdc_window_t;
-typedef struct ltdc_frame_t ltdc_frame_t;
-typedef struct ltdc_laycfg_t ltdc_laycfg_t;
-typedef struct LTDCConfig LTDCConfig;
-typedef enum ltdc_state_t ltdc_state_t;
-typedef struct LTDCDriver LTDCDriver;
-
-/**
- * @name LTDC Data types
- * @{
- */
-
-/**
- * @brief LTDC generic color.
- */
-typedef uint32_t ltdc_color_t;
-
-/**
- * @brief LTDC color aliases.
- * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B).
- * Padding fields are prefixed with <tt>'x'</tt>, and should be clear
- * (all 0) before compression and set (all 1) after expansion.
- */
-typedef union ltdc_coloralias_t {
- struct {
- unsigned b : 8;
- unsigned g : 8;
- unsigned r : 8;
- unsigned a : 8;
- } argb8888; /**< Mapped ARGB-8888 bits.*/
- struct {
- unsigned b : 8;
- unsigned g : 8;
- unsigned r : 8;
- unsigned xa : 8;
- } rgb888; /**< Mapped RGB-888 bits.*/
- struct {
- unsigned xb : 3;
- unsigned b : 5;
- unsigned xg : 2;
- unsigned g : 6;
- unsigned xr : 3;
- unsigned r : 5;
- unsigned xa : 8;
- } rgb565; /**< Mapped RGB-565 bits.*/
- struct {
- unsigned xb : 3;
- unsigned b : 5;
- unsigned xg : 3;
- unsigned g : 5;
- unsigned xr : 3;
- unsigned r : 5;
- unsigned xa : 7;
- unsigned a : 1;
- } argb1555; /**< Mapped ARGB-1555 values.*/
- struct {
- unsigned xb : 4;
- unsigned b : 4;
- unsigned xg : 4;
- unsigned g : 4;
- unsigned xr : 4;
- unsigned r : 4;
- unsigned xa : 4;
- unsigned a : 4;
- } argb4444; /**< Mapped ARGB-4444 values.*/
- struct {
- unsigned l : 8;
- unsigned x : 16;
- unsigned xa : 8;
- } l8; /**< Mapped L-8 bits.*/
- struct {
- unsigned xl : 4;
- unsigned l : 4;
- unsigned x : 16;
- unsigned xa : 4;
- unsigned a : 4;
- } al44; /**< Mapped AL-44 bits.*/
- struct {
- unsigned l : 8;
- unsigned x : 16;
- unsigned a : 8;
- } al88; /**< Mapped AL-88 bits.*/
- ltdc_color_t aliased; /**< Aliased raw bits.*/
-} ltdc_coloralias_t;
-
-/**
- * @brief LTDC layer identifier.
- */
-typedef uint32_t ltdc_layerid_t;
-
-/**
- * @brief LTDC pixel format.
- */
-typedef uint32_t ltdc_pixfmt_t;
-
-/**
- * @brief LTDC blending factor.
- */
-typedef uint32_t ltdc_blendf_t;
-
-/**
- * @brief LTDC ISR callback.
- */
-typedef void (*ltdc_isrcb_t)(LTDCDriver *ltdcp);
-
-/**
- * @brief LTDC window specifications.
- */
-typedef struct ltdc_window_t {
- uint16_t hstart; /**< Horizontal start pixel (left).*/
- uint16_t hstop; /**< Horizontal stop pixel (right).*/
- uint16_t vstart; /**< Vertical start pixel (top).*/
- uint16_t vstop; /**< Vertical stop pixel (bottom).*/
-} ltdc_window_t;
-
-/**
- * @brief LTDC frame specifications.
- */
-typedef struct ltdc_frame_t {
- void *bufferp; /**< Frame buffer address.*/
- uint16_t width; /**< Frame width, in pixels.*/
- uint16_t height; /**< Frame height, in pixels.*/
- size_t pitch; /**< Line pitch, in bytes.*/
- ltdc_pixfmt_t fmt; /**< Pixel format.*/
-} ltdc_frame_t;
-
-/**
- * @brief LTDC configuration flags.
- */
-typedef uint8_t ltdc_flags_t;
-
-/**
- * @brief LTDC startup layer configuration.
- */
-typedef struct ltdc_laycfg_t {
- const ltdc_frame_t *frame; /**< Frame buffer specifications.*/
- const ltdc_window_t *window; /**< Window specifications.*/
- ltdc_color_t def_color; /**< Default color, ARGB-8888.*/
- uint8_t const_alpha; /**< Constant alpha factor.*/
- ltdc_color_t key_color; /**< Color key.*/
- const ltdc_color_t *pal_colors; /**< Palette colors, or @p NULL.*/
- uint16_t pal_length; /**< Palette length, or @p 0.*/
- ltdc_blendf_t blending; /**< Blending factors.*/
- ltdc_flags_t flags; /**< Layer configuration flags.*/
-} ltdc_laycfg_t;
-
-/**
- * @brief LTDC driver configuration.
- */
-typedef struct LTDCConfig {
- /* Display specifications.*/
- uint16_t screen_width; /**< Screen pixel width.*/
- uint16_t screen_height; /**< Screen pixel height.*/
- uint16_t hsync_width; /**< Horizontal sync pixel width.*/
- uint16_t vsync_height; /**< Vertical sync pixel height.*/
- uint16_t hbp_width; /**< Horizontal back porch pixel width.*/
- uint16_t vbp_height; /**< Vertical back porch pixel height.*/
- uint16_t hfp_width; /**< Horizontal front porch pixel width.*/
- uint16_t vfp_height; /**< Vertical front porch pixel height.*/
- ltdc_flags_t flags; /**< Driver configuration flags.*/
-
- /* ISR callbacks.*/
- ltdc_isrcb_t line_isr; /**< Line Interrupt ISR, or @p NULL.*/
- ltdc_isrcb_t rr_isr; /**< Register Reload ISR, or @p NULL.*/
- ltdc_isrcb_t fuerr_isr; /**< FIFO Underrun ISR, or @p NULL.*/
- ltdc_isrcb_t terr_isr; /**< Transfer Error ISR, or @p NULL.*/
-
- /* Layer and color settings.*/
- ltdc_color_t clear_color; /**< Clear screen color, RGB-888.*/
- const ltdc_laycfg_t *bg_laycfg; /**< Background layer specs, or @p NULL.*/
- const ltdc_laycfg_t *fg_laycfg; /**< Foreground layer specs, or @p NULL.*/
-} LTDCConfig;
-
-/**
- * @brief LTDC driver state.
- */
-typedef enum ltdc_state_t {
- LTDC_UNINIT = (0), /**< Not initialized.*/
- LTDC_STOP = (1), /**< Stopped.*/
- LTDC_READY = (2), /**< Ready.*/
- LTDC_ACTIVE = (3), /**< Executing commands.*/
-} ltdc_state_t;
-
-/**
- * @brief LTDC driver.
- */
-typedef struct LTDCDriver {
- ltdc_state_t state; /**< Driver state.*/
- const LTDCConfig *config; /**< Driver configuration.*/
-
- /* Handy computations.*/
- ltdc_window_t active_window; /**< Active window coordinates.*/
-
- /* Multithreading stuff.*/
-#if (TRUE == LTDC_USE_WAIT) || defined(__DOXYGEN__)
- thread_t *thread; /**< Waiting thread.*/
-#endif /* LTDC_USE_WAIT */
-#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION)
-#if (TRUE == CH_CFG_USE_MUTEXES)
- mutex_t lock; /**< Multithreading lock.*/
-#elif (TRUE == CH_CFG_USE_SEMAPHORES)
- semaphore_t lock; /**< Multithreading lock.*/
-#endif
-#endif /* LTDC_USE_MUTUAL_EXCLUSION */
-} LTDCDriver;
-
-/** @} */
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
-
-/**
- * @brief Makes an ARGB-8888 value from byte components.
- *
- * @param[in] a alpha byte component
- * @param[in] r red byte component
- * @param[in] g green byte component
- * @param[in] b blue byte component
- *
- * @return color in ARGB-8888 format
- *
- * @api
- */
-#define ltdcMakeARGB8888(a, r, g, b) \
- ((((ltdc_color_t)(a) & 0xFF) << 24) | \
- (((ltdc_color_t)(r) & 0xFF) << 16) | \
- (((ltdc_color_t)(g) & 0xFF) << 8) | \
- (((ltdc_color_t)(b) & 0xFF) << 0))
-
-/**
- * @brief Compute bytes per pixel.
- * @details Computes the bytes per pixel for the specified pixel format.
- * Rounds to the ceiling.
- *
- * @param[in] fmt pixel format
- *
- * @return bytes per pixel
- *
- * @api
- */
-#define ltdcBytesPerPixel(fmt) \
- ((ltdcBitsPerPixel(fmt) + 7) >> 3)
-
-/*===========================================================================*/
-/* External declarations. */
-/*===========================================================================*/
-
-extern LTDCDriver LTDCD1;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
- /* Driver methods.*/
- void ltdcInit(void);
- void ltdcObjectInit(LTDCDriver *ltdcp);
- ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp);
- ltdc_state_t ltdcGetState(LTDCDriver *ltdcp);
- void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp);
- void ltdcStop(LTDCDriver *ltdcp);
-#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION)
- void ltdcAcquireBusS(LTDCDriver *ltdcp);
- void ltdcAcquireBus(LTDCDriver *ltdcp);
- void ltdcReleaseBusS(LTDCDriver *ltdcp);
- void ltdcReleaseBus(LTDCDriver *ltdcp);
-#endif /* LTDC_USE_MUTUAL_EXCLUSION */
-
- /* Global methods.*/
- ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp);
- ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp);
- void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags);
- void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags);
- bool ltdcIsReloadingI(LTDCDriver *ltdcp);
- bool ltdcIsReloading(LTDCDriver *ltdcp);
- void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately);
- void ltdcStartReload(LTDCDriver *ltdcp, bool immediately);
- void ltdcReloadS(LTDCDriver *ltdcp, bool immediately);
- void ltdcReload(LTDCDriver *ltdcp, bool immediately);
- bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp);
- bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp);
- void ltdcEnableDitheringI(LTDCDriver *ltdcp);
- void ltdcEnableDithering(LTDCDriver *ltdcp);
- void ltdcDisableDitheringI(LTDCDriver *ltdcp);
- void ltdcDisableDithering(LTDCDriver *ltdcp);
- ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp);
- ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp);
- void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c);
- void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c);
- uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp);
- uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp);
- void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line);
- void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line);
- bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp);
- bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp);
- void ltdcEnableLineInterruptI(LTDCDriver *ltdcp);
- void ltdcEnableLineInterrupt(LTDCDriver *ltdcp);
- void ltdcDisableLineInterruptI(LTDCDriver *ltdcp);
- void ltdcDisableLineInterrupt(LTDCDriver *ltdcp);
- void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp);
- void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp);
-
- /* Background layer methods.*/
- ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp);
- ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp);
- void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags);
- void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags);
- bool ltdcBgIsEnabledI(LTDCDriver *ltdcp);
- bool ltdcBgIsEnabled(LTDCDriver *ltdcp);
- void ltdcBgEnableI(LTDCDriver *ltdcp);
- void ltdcBgEnable(LTDCDriver *ltdcp);
- void ltdcBgDisableI(LTDCDriver *ltdcp);
- void ltdcBgDisable(LTDCDriver *ltdcp);
- bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp);
- bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp);
- void ltdcBgEnablePaletteI(LTDCDriver *ltdcp);
- void ltdcBgEnablePalette(LTDCDriver *ltdcp);
- void ltdcBgDisablePaletteI(LTDCDriver *ltdcp);
- void ltdcBgDisablePalette(LTDCDriver *ltdcp);
- void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c);
- void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c);
- void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length);
- void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length);
- ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp);
- ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp);
- void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt);
- void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt);
- bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp);
- bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp);
- void ltdcBgEnableKeyingI(LTDCDriver *ltdcp);
- void ltdcBgEnableKeying(LTDCDriver *ltdcp);
- void ltdcBgDisableKeyingI(LTDCDriver *ltdcp);
- void ltdcBgDisableKeying(LTDCDriver *ltdcp);
- ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp);
- ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp);
- void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c);
- void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c);
- uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp);
- uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp);
- void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a);
- void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a);
- ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp);
- ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp);
- void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c);
- void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c);
- ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp);
- ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp);
- void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf);
- void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf);
- void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp);
- void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp);
- void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp);
- void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp);
- void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp);
- void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp);
- void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep);
- void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep);
- void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep);
- void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep);
- void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp);
- void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp);
- void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp);
- void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp);
- void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp);
- void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp);
- void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp);
- void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp);
-
- /* Foreground layer methods.*/
- ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp);
- ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp);
- void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags);
- void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags);
- bool ltdcFgIsEnabledI(LTDCDriver *ltdcp);
- bool ltdcFgIsEnabled(LTDCDriver *ltdcp);
- void ltdcFgEnableI(LTDCDriver *ltdcp);
- void ltdcFgEnable(LTDCDriver *ltdcp);
- void ltdcFgDisableI(LTDCDriver *ltdcp);
- void ltdcFgDisable(LTDCDriver *ltdcp);
- bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp);
- bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp);
- void ltdcFgEnablePaletteI(LTDCDriver *ltdcp);
- void ltdcFgEnablePalette(LTDCDriver *ltdcp);
- void ltdcFgDisablePaletteI(LTDCDriver *ltdcp);
- void ltdcFgDisablePalette(LTDCDriver *ltdcp);
- void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c);
- void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c);
- void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length);
- void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[],
- uint16_t length);
- ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp);
- ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp);
- void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt);
- void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt);
- bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp);
- bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp);
- void ltdcFgEnableKeyingI(LTDCDriver *ltdcp);
- void ltdcFgEnableKeying(LTDCDriver *ltdcp);
- void ltdcFgDisableKeyingI(LTDCDriver *ltdcp);
- void ltdcFgDisableKeying(LTDCDriver *ltdcp);
- ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp);
- ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp);
- void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c);
- void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c);
- uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp);
- uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp);
- void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a);
- void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a);
- ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp);
- ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp);
- void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c);
- void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c);
- ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp);
- ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp);
- void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf);
- void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf);
- void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp);
- void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp);
- void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp);
- void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp);
- void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp);
- void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp);
- void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep);
- void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep);
- void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep);
- void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep);
- void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp);
- void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp);
- void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp);
- void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp);
- void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp);
- void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp);
- void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp);
- void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp);
-
- /* Helper functions.*/
- size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt);
-#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__)
- ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt);
- ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt);
-#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* STM32_LTDC_USE_LTDC */
-
-#endif /* _STM32_LTDC_H_ */
-
-/** @} */
+/* + Copyright (C) 2013-2015 Andrea Zoppi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_ltdc.h + * @brief LCD-TFT Controller Driver. + * + * @addtogroup ltdc + * @{ + */ + +#ifndef _STM32_LTDC_H_ +#define _STM32_LTDC_H_ + +/** + * @brief Using the LTDC driver. + */ +#if !defined(STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) +#define STM32_LTDC_USE_LTDC (FALSE) +#endif + +#if (TRUE == STM32_LTDC_USE_LTDC) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name LTDC enable flags + * @{ + */ +#define LTDC_EF_ENABLE (1 << 0) /**< LTDC enabled.*/ +#define LTDC_EF_DITHER (1 << 16) /**< Dithering enabled.*/ +#define LTDC_EF_PIXCLK_INVERT (1 << 28) /**< Inverted pixel clock.*/ +#define LTDC_EF_DATAEN_HIGH (1 << 29) /**< Active-high data enable.*/ +#define LTDC_EF_VSYNC_HIGH (1 << 30) /**< Active-high vsync.*/ +#define LTDC_EF_HSYNC_HIGH (1 << 31) /**< Active-high hsync.*/ + +#define LTDC_EF_MASK \ + (LTDC_EF_ENABLE | LTDC_EF_DITHER | LTDC_EF_PIXCLK_INVERT | \ + LTDC_EF_DATAEN_HIGH | LTDC_EF_VSYNC_HIGH | LTDC_EF_HSYNC_HIGH) +/** @} */ + +/** + * @name LTDC layer enable flags + * @{ + */ +#define LTDC_LEF_ENABLE (1 << 0) /**< Layer enabled*/ +#define LTDC_LEF_KEYING (1 << 1) /**< Color keying enabled.*/ +#define LTDC_LEF_PALETTE (1 << 4) /**< Palette enabled.*/ + +#define LTDC_LEF_MASK \ + (LTDC_LEF_ENABLE | LTDC_LEF_KEYING | LTDC_LEF_PALETTE) +/** @} */ + +/** + * @name LTDC pixel formats + * @{ + */ +#define LTDC_FMT_ARGB8888 (0) /**< ARGB-8888 format.*/ +#define LTDC_FMT_RGB888 (1) /**< RGB-888 format.*/ +#define LTDC_FMT_RGB565 (2) /**< RGB-565 format.*/ +#define LTDC_FMT_ARGB1555 (3) /**< ARGB-1555 format.*/ +#define LTDC_FMT_ARGB4444 (4) /**< ARGB-4444 format.*/ +#define LTDC_FMT_L8 (5) /**< L-8 format.*/ +#define LTDC_FMT_AL44 (6) /**< AL-44 format.*/ +#define LTDC_FMT_AL88 (7) /**< AL-88 format.*/ +/** @} */ + +/** + * @name LTDC pixel format aliased raw masks + * @{ + */ +#define LTDC_XMASK_ARGB8888 (0xFFFFFFFF) /**< ARGB-8888 aliased mask.*/ +#define LTDC_XMASK_RGB888 (0x00FFFFFF) /**< RGB-888 aliased mask.*/ +#define LTDC_XMASK_RGB565 (0x00F8FCF8) /**< RGB-565 aliased mask.*/ +#define LTDC_XMASK_ARGB1555 (0x80F8F8F8) /**< ARGB-1555 aliased mask.*/ +#define LTDC_XMASK_ARGB4444 (0xF0F0F0F0) /**< ARGB-4444 aliased mask.*/ +#define LTDC_XMASK_L8 (0x000000FF) /**< L-8 aliased mask.*/ +#define LTDC_XMASK_AL44 (0xF00000F0) /**< AL-44 aliased mask.*/ +#define LTDC_XMASK_AL88 (0xFF0000FF) /**< AL-88 aliased mask.*/ +/** @} */ + +/** + * @name LTDC blending factors + * @{ + */ +#define LTDC_BLEND_FIX1_FIX2 (0x0405) /**< cnst1; 1 - cnst2 */ +#define LTDC_BLEND_FIX1_MOD2 (0x0407) /**< cnst1; 1 - a2 * cnst2 */ +#define LTDC_BLEND_MOD1_FIX2 (0x0605) /**< a1 * cnst1; 1 - cnst2 */ +#define LTDC_BLEND_MOD1_MOD2 (0x0607) /**< a1 * cnst1; 1 - a2 * cnst2 */ +/** @} */ + +/** + * @name LTDC parameter bounds + * @{ + */ + +#define LTDC_MIN_SCREEN_WIDTH (1) +#define LTDC_MIN_SCREEN_HEIGHT (1) +#define LTDC_MAX_SCREEN_WIDTH (800) +#define LTDC_MAX_SCREEN_HEIGHT (600) + +#define LTDC_MIN_HSYNC_WIDTH (1) +#define LTDC_MIN_VSYNC_HEIGHT (1) +#define LTDC_MAX_HSYNC_WIDTH (1 << 12) +#define LTDC_MAX_VSYNC_HEIGHT (1 << 11) + +#define LTDC_MIN_HBP_WIDTH (0) +#define LTDC_MIN_VBP_HEIGHT (0) +#define LTDC_MAX_HBP_WIDTH (1 << 12) +#define LTDC_MAX_VBP_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_HBP_WIDTH (1) +#define LTDC_MIN_ACC_VBP_HEIGHT (1) +#define LTDC_MAX_ACC_HBP_WIDTH (1 << 12) +#define LTDC_MAX_ACC_VBP_HEIGHT (1 << 11) + +#define LTDC_MIN_HFP_WIDTH (0) +#define LTDC_MIN_VFP_HEIGHT (0) +#define LTDC_MAX_HFP_WIDTH (1 << 12) +#define LTDC_MAX_VFP_HEIGHT (1 << 11) + +#define LTDC_MIN_ACTIVE_WIDTH (0) +#define LTDC_MIN_ACTIVE_HEIGHT (0) +#define LTDC_MAX_ACTIVE_WIDTH (1 << 12) +#define LTDC_MAX_ACTIVE_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_ACTIVE_WIDTH (1) +#define LTDC_MIN_ACC_ACTIVE_HEIGHT (1) +#define LTDC_MAX_ACC_ACTIVE_WIDTH (1 << 12) +#define LTDC_MAX_ACC_ACTIVE_HEIGHT (1 << 11) + +#define LTDC_MIN_ACC_TOTAL_WIDTH (1) +#define LTDC_MIN_ACC_TOTAL_HEIGHT (1) +#define LTDC_MAX_ACC_TOTAL_WIDTH (1 << 12) +#define LTDC_MAX_ACC_TOTAL_HEIGHT (1 << 11) + +#define LTDC_MIN_LINE_INTERRUPT_POS (0) +#define LTDC_MAX_LINE_INTERRUPT_POS ((1 << 11) - 1) + +#define LTDC_MIN_WINDOW_HSTART (0) +#define LTDC_MIN_WINDOW_HSTART (0) +#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) +#define LTDC_MAX_WINDOW_HSTOP ((1 << 12) - 1) + +#define LTDC_MIN_WINDOW_VSTART (0) +#define LTDC_MIN_WINDOW_VSTART (0) +#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) +#define LTDC_MAX_WINDOW_VSTOP ((1 << 11) - 1) + +#define LTDC_MIN_FRAME_WIDTH_BYTES (0) +#define LTDC_MIN_FRAME_HEIGHT_LINES (0) +#define LTDC_MIN_FRAME_PITCH_BYTES (0) +#define LTDC_MAX_FRAME_WIDTH_BYTES ((1 << 13) - 1 - 3) +#define LTDC_MAX_FRAME_HEIGHT_LINES ((1 << 11) - 1) +#define LTDC_MAX_FRAME_PITCH_BYTES ((1 << 13) - 1) + +#define LTDC_MIN_PIXFMT_ID (0) +#define LTDC_MAX_PIXFMT_ID (7) + +#define LTDC_MAX_PALETTE_LENGTH (256) + +/** @} */ + +/** + * @name LTDC basic ARGB-8888 colors. + * @{ + */ +/* Microsoft Windows default 16-color palette.*/ +#define LTDC_COLOR_BLACK (0xFF000000) +#define LTDC_COLOR_MAROON (0xFF800000) +#define LTDC_COLOR_GREEN (0xFF008000) +#define LTDC_COLOR_OLIVE (0xFF808000) +#define LTDC_COLOR_NAVY (0xFF000080) +#define LTDC_COLOR_PURPLE (0xFF800080) +#define LTDC_COLOR_TEAL (0xFF008080) +#define LTDC_COLOR_SILVER (0xFFC0C0C0) +#define LTDC_COLOR_GRAY (0xFF808080) +#define LTDC_COLOR_RED (0xFFFF0000) +#define LTDC_COLOR_LIME (0xFF00FF00) +#define LTDC_COLOR_YELLOW (0xFFFFFF00) +#define LTDC_COLOR_BLUE (0xFF0000FF) +#define LTDC_COLOR_FUCHSIA (0xFFFF00FF) +#define LTDC_COLOR_AQUA (0xFF00FFFF) +#define LTDC_COLOR_WHITE (0xFFFFFFFF) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name LTDC configuration options + * @{ + */ + +/** + * @brief LTDC event interrupt priority level setting. + */ +#if !defined(STM32_LTDC_EV_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_LTDC_EV_IRQ_PRIORITY (11) +#endif + +/** + * @brief LTDC error interrupt priority level setting. + */ +#if !defined(STM32_LTDC_ER_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define STM32_LTDC_ER_IRQ_PRIORITY (11) +#endif + +/** + * @brief Enables synchronous APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_WAIT) || defined(__DOXYGEN__) +#define LTDC_USE_WAIT (TRUE) +#endif + +/** + * @brief Enables the @p ltdcAcquireBus() and @p ltdcReleaseBus() APIs. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define LTDC_USE_MUTUAL_EXCLUSION (TRUE) +#endif + +/** + * @brief Provides software color conversion functions. + * @note Disabling this option saves both code and data space. + */ +#if !defined(LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) +#define LTDC_USE_SOFTWARE_CONVERSIONS (TRUE) +#endif + +/** + * @brief Enables checks for LTDC functions. + * @note Disabling this option saves both code and data space. + * @note Disabling checks by ChibiOS will automatically disable LTDC checks. + */ +#if !defined(LTDC_USE_CHECKS) || defined(__DOXYGEN__) +#define LTDC_USE_CHECKS (TRUE) +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if (TRUE != STM32_HAS_LTDC) +#error "LTDC must be present when using the LTDC subsystem" +#endif + +#if (TRUE == STM32_LTDC_USE_LTDC) && (TRUE != STM32_HAS_LTDC) +#error "LTDC not present in the selected device" +#endif + +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE != CH_CFG_USE_MUTEXES) && (TRUE != CH_CFG_USE_SEMAPHORES) +#error "LTDC_USE_MUTUAL_EXCLUSION requires CH_CFG_USE_MUTEXES and/or CH_CFG_USE_SEMAPHORES" +#endif +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/* Complex types forwarding.*/ +typedef union ltdc_coloralias_t ltdc_coloralias_t; +typedef struct ltdc_window_t ltdc_window_t; +typedef struct ltdc_frame_t ltdc_frame_t; +typedef struct ltdc_laycfg_t ltdc_laycfg_t; +typedef struct LTDCConfig LTDCConfig; +typedef enum ltdc_state_t ltdc_state_t; +typedef struct LTDCDriver LTDCDriver; + +/** + * @name LTDC Data types + * @{ + */ + +/** + * @brief LTDC generic color. + */ +typedef uint32_t ltdc_color_t; + +/** + * @brief LTDC color aliases. + * @detail Mapped with ARGB-8888, except for luminance (L mapped onto B). + * Padding fields are prefixed with <tt>'x'</tt>, and should be clear + * (all 0) before compression and set (all 1) after expansion. + */ +typedef union ltdc_coloralias_t { + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned a : 8; + } argb8888; /**< Mapped ARGB-8888 bits.*/ + struct { + unsigned b : 8; + unsigned g : 8; + unsigned r : 8; + unsigned xa : 8; + } rgb888; /**< Mapped RGB-888 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 2; + unsigned g : 6; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 8; + } rgb565; /**< Mapped RGB-565 bits.*/ + struct { + unsigned xb : 3; + unsigned b : 5; + unsigned xg : 3; + unsigned g : 5; + unsigned xr : 3; + unsigned r : 5; + unsigned xa : 7; + unsigned a : 1; + } argb1555; /**< Mapped ARGB-1555 values.*/ + struct { + unsigned xb : 4; + unsigned b : 4; + unsigned xg : 4; + unsigned g : 4; + unsigned xr : 4; + unsigned r : 4; + unsigned xa : 4; + unsigned a : 4; + } argb4444; /**< Mapped ARGB-4444 values.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned xa : 8; + } l8; /**< Mapped L-8 bits.*/ + struct { + unsigned xl : 4; + unsigned l : 4; + unsigned x : 16; + unsigned xa : 4; + unsigned a : 4; + } al44; /**< Mapped AL-44 bits.*/ + struct { + unsigned l : 8; + unsigned x : 16; + unsigned a : 8; + } al88; /**< Mapped AL-88 bits.*/ + ltdc_color_t aliased; /**< Aliased raw bits.*/ +} ltdc_coloralias_t; + +/** + * @brief LTDC layer identifier. + */ +typedef uint32_t ltdc_layerid_t; + +/** + * @brief LTDC pixel format. + */ +typedef uint32_t ltdc_pixfmt_t; + +/** + * @brief LTDC blending factor. + */ +typedef uint32_t ltdc_blendf_t; + +/** + * @brief LTDC ISR callback. + */ +typedef void (*ltdc_isrcb_t)(LTDCDriver *ltdcp); + +/** + * @brief LTDC window specifications. + */ +typedef struct ltdc_window_t { + uint16_t hstart; /**< Horizontal start pixel (left).*/ + uint16_t hstop; /**< Horizontal stop pixel (right).*/ + uint16_t vstart; /**< Vertical start pixel (top).*/ + uint16_t vstop; /**< Vertical stop pixel (bottom).*/ +} ltdc_window_t; + +/** + * @brief LTDC frame specifications. + */ +typedef struct ltdc_frame_t { + void *bufferp; /**< Frame buffer address.*/ + uint16_t width; /**< Frame width, in pixels.*/ + uint16_t height; /**< Frame height, in pixels.*/ + size_t pitch; /**< Line pitch, in bytes.*/ + ltdc_pixfmt_t fmt; /**< Pixel format.*/ +} ltdc_frame_t; + +/** + * @brief LTDC configuration flags. + */ +typedef uint8_t ltdc_flags_t; + +/** + * @brief LTDC startup layer configuration. + */ +typedef struct ltdc_laycfg_t { + const ltdc_frame_t *frame; /**< Frame buffer specifications.*/ + const ltdc_window_t *window; /**< Window specifications.*/ + ltdc_color_t def_color; /**< Default color, ARGB-8888.*/ + uint8_t const_alpha; /**< Constant alpha factor.*/ + ltdc_color_t key_color; /**< Color key.*/ + const ltdc_color_t *pal_colors; /**< Palette colors, or @p NULL.*/ + uint16_t pal_length; /**< Palette length, or @p 0.*/ + ltdc_blendf_t blending; /**< Blending factors.*/ + ltdc_flags_t flags; /**< Layer configuration flags.*/ +} ltdc_laycfg_t; + +/** + * @brief LTDC driver configuration. + */ +typedef struct LTDCConfig { + /* Display specifications.*/ + uint16_t screen_width; /**< Screen pixel width.*/ + uint16_t screen_height; /**< Screen pixel height.*/ + uint16_t hsync_width; /**< Horizontal sync pixel width.*/ + uint16_t vsync_height; /**< Vertical sync pixel height.*/ + uint16_t hbp_width; /**< Horizontal back porch pixel width.*/ + uint16_t vbp_height; /**< Vertical back porch pixel height.*/ + uint16_t hfp_width; /**< Horizontal front porch pixel width.*/ + uint16_t vfp_height; /**< Vertical front porch pixel height.*/ + ltdc_flags_t flags; /**< Driver configuration flags.*/ + + /* ISR callbacks.*/ + ltdc_isrcb_t line_isr; /**< Line Interrupt ISR, or @p NULL.*/ + ltdc_isrcb_t rr_isr; /**< Register Reload ISR, or @p NULL.*/ + ltdc_isrcb_t fuerr_isr; /**< FIFO Underrun ISR, or @p NULL.*/ + ltdc_isrcb_t terr_isr; /**< Transfer Error ISR, or @p NULL.*/ + + /* Layer and color settings.*/ + ltdc_color_t clear_color; /**< Clear screen color, RGB-888.*/ + const ltdc_laycfg_t *bg_laycfg; /**< Background layer specs, or @p NULL.*/ + const ltdc_laycfg_t *fg_laycfg; /**< Foreground layer specs, or @p NULL.*/ +} LTDCConfig; + +/** + * @brief LTDC driver state. + */ +typedef enum ltdc_state_t { + LTDC_UNINIT = (0), /**< Not initialized.*/ + LTDC_STOP = (1), /**< Stopped.*/ + LTDC_READY = (2), /**< Ready.*/ + LTDC_ACTIVE = (3), /**< Executing commands.*/ +} ltdc_state_t; + +/** + * @brief LTDC driver. + */ +typedef struct LTDCDriver { + ltdc_state_t state; /**< Driver state.*/ + const LTDCConfig *config; /**< Driver configuration.*/ + + /* Handy computations.*/ + ltdc_window_t active_window; /**< Active window coordinates.*/ + + /* Multithreading stuff.*/ +#if (TRUE == LTDC_USE_WAIT) || defined(__DOXYGEN__) + thread_t *thread; /**< Waiting thread.*/ +#endif /* LTDC_USE_WAIT */ +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) +#if (TRUE == CH_CFG_USE_MUTEXES) + mutex_t lock; /**< Multithreading lock.*/ +#elif (TRUE == CH_CFG_USE_SEMAPHORES) + semaphore_t lock; /**< Multithreading lock.*/ +#endif +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ +} LTDCDriver; + +/** @} */ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Makes an ARGB-8888 value from byte components. + * + * @param[in] a alpha byte component + * @param[in] r red byte component + * @param[in] g green byte component + * @param[in] b blue byte component + * + * @return color in ARGB-8888 format + * + * @api + */ +#define ltdcMakeARGB8888(a, r, g, b) \ + ((((ltdc_color_t)(a) & 0xFF) << 24) | \ + (((ltdc_color_t)(r) & 0xFF) << 16) | \ + (((ltdc_color_t)(g) & 0xFF) << 8) | \ + (((ltdc_color_t)(b) & 0xFF) << 0)) + +/** + * @brief Compute bytes per pixel. + * @details Computes the bytes per pixel for the specified pixel format. + * Rounds to the ceiling. + * + * @param[in] fmt pixel format + * + * @return bytes per pixel + * + * @api + */ +#define ltdcBytesPerPixel(fmt) \ + ((ltdcBitsPerPixel(fmt) + 7) >> 3) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern LTDCDriver LTDCD1; + +#ifdef __cplusplus +extern "C" { +#endif + /* Driver methods.*/ + void ltdcInit(void); + void ltdcObjectInit(LTDCDriver *ltdcp); + ltdc_state_t ltdcGetStateI(LTDCDriver *ltdcp); + ltdc_state_t ltdcGetState(LTDCDriver *ltdcp); + void ltdcStart(LTDCDriver *ltdcp, const LTDCConfig *configp); + void ltdcStop(LTDCDriver *ltdcp); +#if (TRUE == LTDC_USE_MUTUAL_EXCLUSION) + void ltdcAcquireBusS(LTDCDriver *ltdcp); + void ltdcAcquireBus(LTDCDriver *ltdcp); + void ltdcReleaseBusS(LTDCDriver *ltdcp); + void ltdcReleaseBus(LTDCDriver *ltdcp); +#endif /* LTDC_USE_MUTUAL_EXCLUSION */ + + /* Global methods.*/ + ltdc_flags_t ltdcGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcGetEnableFlags(LTDCDriver *ltdcp); + void ltdcSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcIsReloadingI(LTDCDriver *ltdcp); + bool ltdcIsReloading(LTDCDriver *ltdcp); + void ltdcStartReloadI(LTDCDriver *ltdcp, bool immediately); + void ltdcStartReload(LTDCDriver *ltdcp, bool immediately); + void ltdcReloadS(LTDCDriver *ltdcp, bool immediately); + void ltdcReload(LTDCDriver *ltdcp, bool immediately); + bool ltdcIsDitheringEnabledI(LTDCDriver *ltdcp); + bool ltdcIsDitheringEnabled(LTDCDriver *ltdcp); + void ltdcEnableDitheringI(LTDCDriver *ltdcp); + void ltdcEnableDithering(LTDCDriver *ltdcp); + void ltdcDisableDitheringI(LTDCDriver *ltdcp); + void ltdcDisableDithering(LTDCDriver *ltdcp); + ltdc_color_t ltdcGetClearColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcGetClearColor(LTDCDriver *ltdcp); + void ltdcSetClearColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcSetClearColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint16_t ltdcGetLineInterruptPosI(LTDCDriver *ltdcp); + uint16_t ltdcGetLineInterruptPos(LTDCDriver *ltdcp); + void ltdcSetLineInterruptPosI(LTDCDriver *ltdcp, uint16_t line); + void ltdcSetLineInterruptPos(LTDCDriver *ltdcp, uint16_t line); + bool ltdcIsLineInterruptEnabledI(LTDCDriver *ltdcp); + bool ltdcIsLineInterruptEnabled(LTDCDriver *ltdcp); + void ltdcEnableLineInterruptI(LTDCDriver *ltdcp); + void ltdcEnableLineInterrupt(LTDCDriver *ltdcp); + void ltdcDisableLineInterruptI(LTDCDriver *ltdcp); + void ltdcDisableLineInterrupt(LTDCDriver *ltdcp); + void ltdcGetCurrentPosI(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); + void ltdcGetCurrentPos(LTDCDriver *ltdcp, uint16_t *xp, uint16_t *yp); + + /* Background layer methods.*/ + ltdc_flags_t ltdcBgGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcBgGetEnableFlags(LTDCDriver *ltdcp); + void ltdcBgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcBgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcBgIsEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsEnabled(LTDCDriver *ltdcp); + void ltdcBgEnableI(LTDCDriver *ltdcp); + void ltdcBgEnable(LTDCDriver *ltdcp); + void ltdcBgDisableI(LTDCDriver *ltdcp); + void ltdcBgDisable(LTDCDriver *ltdcp); + bool ltdcBgIsPaletteEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsPaletteEnabled(LTDCDriver *ltdcp); + void ltdcBgEnablePaletteI(LTDCDriver *ltdcp); + void ltdcBgEnablePalette(LTDCDriver *ltdcp); + void ltdcBgDisablePaletteI(LTDCDriver *ltdcp); + void ltdcBgDisablePalette(LTDCDriver *ltdcp); + void ltdcBgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcBgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcBgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + void ltdcBgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + ltdc_pixfmt_t ltdcBgGetPixelFormatI(LTDCDriver *ltdcp); + ltdc_pixfmt_t ltdcBgGetPixelFormat(LTDCDriver *ltdcp); + void ltdcBgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + void ltdcBgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + bool ltdcBgIsKeyingEnabledI(LTDCDriver *ltdcp); + bool ltdcBgIsKeyingEnabled(LTDCDriver *ltdcp); + void ltdcBgEnableKeyingI(LTDCDriver *ltdcp); + void ltdcBgEnableKeying(LTDCDriver *ltdcp); + void ltdcBgDisableKeyingI(LTDCDriver *ltdcp); + void ltdcBgDisableKeying(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetKeyingColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetKeyingColor(LTDCDriver *ltdcp); + void ltdcBgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcBgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint8_t ltdcBgGetConstantAlphaI(LTDCDriver *ltdcp); + uint8_t ltdcBgGetConstantAlpha(LTDCDriver *ltdcp); + void ltdcBgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); + void ltdcBgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); + ltdc_color_t ltdcBgGetDefaultColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcBgGetDefaultColor(LTDCDriver *ltdcp); + void ltdcBgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcBgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); + ltdc_blendf_t ltdcBgGetBlendingFactorsI(LTDCDriver *ltdcp); + ltdc_blendf_t ltdcBgGetBlendingFactors(LTDCDriver *ltdcp); + void ltdcBgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcBgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcBgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcBgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcBgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcBgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcBgSetInvalidWindowI(LTDCDriver *ltdcp); + void ltdcBgSetInvalidWindow(LTDCDriver *ltdcp); + void ltdcBgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcBgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcBgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void ltdcBgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void *ltdcBgGetFrameAddressI(LTDCDriver *ltdcp); + void *ltdcBgGetFrameAddress(LTDCDriver *ltdcp); + void ltdcBgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); + void ltdcBgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); + void ltdcBgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcBgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcBgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + void ltdcBgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + + /* Foreground layer methods.*/ + ltdc_flags_t ltdcFgGetEnableFlagsI(LTDCDriver *ltdcp); + ltdc_flags_t ltdcFgGetEnableFlags(LTDCDriver *ltdcp); + void ltdcFgSetEnableFlagsI(LTDCDriver *ltdcp, ltdc_flags_t flags); + void ltdcFgSetEnableFlags(LTDCDriver *ltdcp, ltdc_flags_t flags); + bool ltdcFgIsEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsEnabled(LTDCDriver *ltdcp); + void ltdcFgEnableI(LTDCDriver *ltdcp); + void ltdcFgEnable(LTDCDriver *ltdcp); + void ltdcFgDisableI(LTDCDriver *ltdcp); + void ltdcFgDisable(LTDCDriver *ltdcp); + bool ltdcFgIsPaletteEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsPaletteEnabled(LTDCDriver *ltdcp); + void ltdcFgEnablePaletteI(LTDCDriver *ltdcp); + void ltdcFgEnablePalette(LTDCDriver *ltdcp); + void ltdcFgDisablePaletteI(LTDCDriver *ltdcp); + void ltdcFgDisablePalette(LTDCDriver *ltdcp); + void ltdcFgSetPaletteColorI(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcFgSetPaletteColor(LTDCDriver *ltdcp, uint8_t slot, ltdc_color_t c); + void ltdcFgSetPaletteI(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + void ltdcFgSetPalette(LTDCDriver *ltdcp, const ltdc_color_t colors[], + uint16_t length); + ltdc_pixfmt_t ltdcFgGetPixelFormatI(LTDCDriver *ltdcp); + ltdc_pixfmt_t ltdcFgGetPixelFormat(LTDCDriver *ltdcp); + void ltdcFgSetPixelFormatI(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + void ltdcFgSetPixelFormat(LTDCDriver *ltdcp, ltdc_pixfmt_t fmt); + bool ltdcFgIsKeyingEnabledI(LTDCDriver *ltdcp); + bool ltdcFgIsKeyingEnabled(LTDCDriver *ltdcp); + void ltdcFgEnableKeyingI(LTDCDriver *ltdcp); + void ltdcFgEnableKeying(LTDCDriver *ltdcp); + void ltdcFgDisableKeyingI(LTDCDriver *ltdcp); + void ltdcFgDisableKeying(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetKeyingColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetKeyingColor(LTDCDriver *ltdcp); + void ltdcFgSetKeyingColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcFgSetKeyingColor(LTDCDriver *ltdcp, ltdc_color_t c); + uint8_t ltdcFgGetConstantAlphaI(LTDCDriver *ltdcp); + uint8_t ltdcFgGetConstantAlpha(LTDCDriver *ltdcp); + void ltdcFgSetConstantAlphaI(LTDCDriver *ltdcp, uint8_t a); + void ltdcFgSetConstantAlpha(LTDCDriver *ltdcp, uint8_t a); + ltdc_color_t ltdcFgGetDefaultColorI(LTDCDriver *ltdcp); + ltdc_color_t ltdcFgGetDefaultColor(LTDCDriver *ltdcp); + void ltdcFgSetDefaultColorI(LTDCDriver *ltdcp, ltdc_color_t c); + void ltdcFgSetDefaultColor(LTDCDriver *ltdcp, ltdc_color_t c); + ltdc_blendf_t ltdcFgGetBlendingFactorsI(LTDCDriver *ltdcp); + ltdc_blendf_t ltdcFgGetBlendingFactors(LTDCDriver *ltdcp); + void ltdcFgSetBlendingFactorsI(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcFgSetBlendingFactors(LTDCDriver *ltdcp, ltdc_blendf_t bf); + void ltdcFgGetWindowI(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcFgGetWindow(LTDCDriver *ltdcp, ltdc_window_t *windowp); + void ltdcFgSetWindowI(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcFgSetWindow(LTDCDriver *ltdcp, const ltdc_window_t *windowp); + void ltdcFgSetInvalidWindowI(LTDCDriver *ltdcp); + void ltdcFgSetInvalidWindow(LTDCDriver *ltdcp); + void ltdcFgGetFrameI(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcFgGetFrame(LTDCDriver *ltdcp, ltdc_frame_t *framep); + void ltdcFgSetFrameI(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void ltdcFgSetFrame(LTDCDriver *ltdcp, const ltdc_frame_t *framep); + void *ltdcFgGetFrameAddressI(LTDCDriver *ltdcp); + void *ltdcFgGetFrameAddress(LTDCDriver *ltdcp); + void ltdcFgSetFrameAddressI(LTDCDriver *ltdcp, void *bufferp); + void ltdcFgSetFrameAddress(LTDCDriver *ltdcp, void *bufferp); + void ltdcFgGetLayerI(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcFgGetLayer(LTDCDriver *ltdcp, ltdc_laycfg_t *cfgp); + void ltdcFgSetConfigI(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + void ltdcFgSetConfig(LTDCDriver *ltdcp, const ltdc_laycfg_t *cfgp); + + /* Helper functions.*/ + size_t ltdcBitsPerPixel(ltdc_pixfmt_t fmt); +#if (TRUE == LTDC_USE_SOFTWARE_CONVERSIONS) || defined(__DOXYGEN__) + ltdc_color_t ltdcFromARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); + ltdc_color_t ltdcToARGB8888(ltdc_color_t c, ltdc_pixfmt_t fmt); +#endif /* LTDC_USE_SOFTWARE_CONVERSIONS */ + +#ifdef __cplusplus +} +#endif + +#endif /* STM32_LTDC_USE_LTDC */ + +#endif /* _STM32_LTDC_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c index c04278e..c04278e 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c diff --git a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h index 927eb6f..927eb6f 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.h +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.h diff --git a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c index 635e9b2..8ab6176 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c @@ -37,7 +37,7 @@ #if HAL_USE_TIMCAP || defined(__DOXYGEN__) #include "stm32_tim.h" -#include "timcap.h" +#include "hal_timcap.h" /*===========================================================================*/ /* Driver local definitions. */ diff --git a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h index d39c438..d39c438 100644 --- a/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.h +++ b/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.h diff --git a/os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h b/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h index 268c9bf..ca2dc49 100644 --- a/os/hal/ports/STM32/LLD/USBHv1/stm32_otg.h +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_stm32_otg.h @@ -1,929 +1,929 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file stm32_otg.h
- * @brief STM32 OTG registers layout header.
- *
- * @addtogroup USB
- * @{
- */
-
-
-#ifndef _STM32_OTG_H_
-#define _STM32_OTG_H_
-
-/**
- * @brief Number of the implemented endpoints in OTG_FS.
- * @details This value does not include the endpoint 0 that is always present.
- */
-#define STM32_OTG1_ENDOPOINTS_NUMBER 3
-
-/**
- * @brief Number of the implemented endpoints in OTG_HS.
- * @details This value does not include the endpoint 0 that is always present.
- */
-#define STM32_OTG2_ENDOPOINTS_NUMBER 5
-
-/**
- * @brief OTG_FS FIFO memory size in words.
- */
-#define STM32_OTG1_FIFO_MEM_SIZE 320
-
-/**
- * @brief OTG_HS FIFO memory size in words.
- */
-#define STM32_OTG2_FIFO_MEM_SIZE 1024
-
-/**
- * @brief Host channel registers group.
- */
-typedef struct {
- volatile uint32_t HCCHAR; /**< @brief Host channel characteristics
- register. */
- volatile uint32_t resvd8;
- volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/
- volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask
- register. */
- volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size
- register. */
- volatile uint32_t resvd14;
- volatile uint32_t resvd18;
- volatile uint32_t resvd1c;
-} stm32_otg_host_chn_t;
-
-/**
- * @brief Device input endpoint registers group.
- */
-typedef struct {
- volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint
- control register. */
- volatile uint32_t resvd4;
- volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt
- register. */
- volatile uint32_t resvdC;
- volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size
- register. */
- volatile uint32_t resvd14;
- volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO
- status register. */
- volatile uint32_t resvd1C;
-} stm32_otg_in_ep_t;
-
-/**
- * @brief Device output endpoint registers group.
- */
-typedef struct {
- volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint
- control register. */
- volatile uint32_t resvd4;
- volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt
- register. */
- volatile uint32_t resvdC;
- volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer
- size register. */
- volatile uint32_t resvd14;
- volatile uint32_t resvd18;
- volatile uint32_t resvd1C;
-} stm32_otg_out_ep_t;
-
-/**
- * @brief USB registers memory map.
- */
-typedef struct {
- volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/
- volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */
- volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */
- volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */
- volatile uint32_t GRSTCTL; /**< @brief Reset register size. */
- volatile uint32_t GINTSTS; /**< @brief Interrupt register. */
- volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */
- volatile uint32_t GRXSTSR; /**< @brief Receive status debug read
- register. */
- volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop
- register. */
- volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */
- volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size
- register. */
- volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue
- status register. */
- volatile uint32_t resvd30;
- volatile uint32_t resvd34;
- volatile uint32_t GCCFG; /**< @brief General core configuration. */
- volatile uint32_t CID; /**< @brief Core ID register. */
- volatile uint32_t resvd58[48];
- volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size
- register. */
- volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO
- size registers. */
- volatile uint32_t resvd140[176];
- volatile uint32_t HCFG; /**< @brief Host configuration register. */
- volatile uint32_t HFIR; /**< @brief Host frame interval register. */
- volatile uint32_t HFNUM; /**< @brief Host frame number/frame time
- Remaining register. */
- volatile uint32_t resvd40C;
- volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue
- status register. */
- volatile uint32_t HAINT; /**< @brief Host all channels interrupt
- register. */
- volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask
- register. */
- volatile uint32_t resvd41C[9];
- volatile uint32_t HPRT; /**< @brief Host port control and status
- register. */
- volatile uint32_t resvd444[47];
- stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */
- volatile uint32_t resvd700[64];
- volatile uint32_t DCFG; /**< @brief Device configuration register. */
- volatile uint32_t DCTL; /**< @brief Device control register. */
- volatile uint32_t DSTS; /**< @brief Device status register. */
- volatile uint32_t resvd80C;
- volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common
- interrupt mask register. */
- volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common
- interrupt mask register. */
- volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt
- register. */
- volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt
- mask register. */
- volatile uint32_t resvd820;
- volatile uint32_t resvd824;
- volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time
- register. */
- volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time
- register. */
- volatile uint32_t resvd830;
- volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty
- interrupt mask register. */
- volatile uint32_t resvd838;
- volatile uint32_t resvd83C;
- volatile uint32_t resvd840[16];
- volatile uint32_t resvd880[16];
- volatile uint32_t resvd8C0[16];
- stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */
- stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */
- volatile uint32_t resvdD00[64];
- volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control
- register. */
- volatile uint32_t resvdE04[127];
- volatile uint32_t FIFO[16][1024];
-} stm32_otg_t;
-
-/**
- * @name GOTGCTL register bit definitions
- * @{
- */
-#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */
-#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */
-#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */
-#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */
-#define GOTGCTL_EHEN (1U<<12)
-#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */
-#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */
-#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */
-#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */
-#define GOTGCTL_BVALOVAL (1U<<7)
-#define GOTGCTL_BVALOEN (1U<<6)
-#define GOTGCTL_AVALOVAL (1U<<5)
-#define GOTGCTL_AVALOEN (1U<<4)
-#define GOTGCTL_VBVALOVAL (1U<<3)
-#define GOTGCTL_VBVALOEN (1U<<2)
-#define GOTGCTL_SRQ (1U<<1) /**< Session request. */
-#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */
-/** @} */
-
-/**
- * @name GOTGINT register bit definitions
- * @{
- */
-#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */
-#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */
-#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */
-#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success
- status change. */
-#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success
- status change. */
-#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */
-/** @} */
-
-/**
- * @name GAHBCFG register bit definitions
- * @{
- */
-#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty
- level. */
-#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty
- level. */
-#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */
-#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS
- only). */
-#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS
- only). */
-#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */
-/** @} */
-
-/**
- * @name GUSBCFG register bit definitions
- * @{
- */
-#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */
-#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */
-#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */
-#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field
- mask. */
-#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field
- value. */
-#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */
-#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */
-#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or
- USB 1.1 Full-Speed serial
- transceiver Select. */
-#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration
- field mask. */
-#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration
- field value. */
-/** @} */
-
-/**
- * @name GRSTCTL register bit definitions
- * @{
- */
-#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */
-#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */
-#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */
-#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */
-#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */
-#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */
-#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */
-#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */
-/** @} */
-
-/**
- * @name GINTSTS register bit definitions
- * @{
- */
-#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup
- detected interrupt. */
-#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session
- detected interrupt. */
-#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected
- interrupt. */
-#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/
-#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */
-#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */
-#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */
-#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic
- transfer. */
-#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT
- transfer. */
-#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN
- transfer. */
-#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */
-#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */
-#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame
- interrupt. */
-#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet
- dropped interrupt. */
-#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */
-#define GINTSTS_USBRST (1U<<12) /**< USB reset. */
-#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */
-#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */
-#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */
-#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK
- effective. */
-#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */
-#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */
-#define GINTSTS_SOF (1U<<3) /**< Start of frame. */
-#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */
-#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */
-#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */
-/** @} */
-
-/**
- * @name GINTMSK register bit definitions
- * @{
- */
-#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup
- detected interrupt mask. */
-#define GINTMSK_SRQM (1U<<30) /**< Session request/New session
- detected interrupt mask. */
-#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected
- interrupt mask. */
-#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change
- mask. */
-#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/
-#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt
- mask. */
-#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */
-#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic
- transfer mask. */
-#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT
- transfer mask. */
-#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN
- transfer mask. */
-#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt
- mask. */
-#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt
- mask. */
-#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame
- interrupt mask. */
-#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet
- dropped interrupt mask. */
-#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */
-#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */
-#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */
-#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */
-#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective
- mask. */
-#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK
- effective mask. */
-#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty
- mask. */
-#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty
- mask. */
-#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/
-#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */
-#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt
- mask. */
-/** @} */
-
-/**
- * @name GRXSTSR register bit definitions
- * @{
- */
-#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */
-#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */
-#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1)
-#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2)
-#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3)
-#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4)
-#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6)
-#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */
-#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */
-#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
-#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */
-#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */
-#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */
-#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
-#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
-/** @} */
-
-/**
- * @name GRXSTSP register bit definitions
- * @{
- */
-#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */
-#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */
-#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1)
-#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2)
-#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3)
-#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4)
-#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6)
-#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */
-#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */
-#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */
-#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */
-#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */
-#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */
-#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */
-#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */
-#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */
-#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */
-/** @} */
-
-/**
- * @name GRXFSIZ register bit definitions
- * @{
- */
-#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */
-#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */
-/** @} */
-
-/**
- * @name DIEPTXFx register bit definitions
- * @{
- */
-#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth
- mask. */
-#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth
- value. */
-#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit
- RAM start address mask. */
-#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit
- RAM start address value. */
-/** @} */
-
-/**
- * @name GCCFG register bit definitions
- * @{
- */
-#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */
-#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */
-#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B"
- device. */
-#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A"
- device. */
-#define GCCFG_PWRDWN (1U<<16) /**< Power down. */
-/** @} */
-
-/**
- * @name HPTXFSIZ register bit definitions
- * @{
- */
-#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO
- depth mask. */
-#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO
- depth value. */
-#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO
- Start address mask. */
-#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO
- start address value. */
-/** @} */
-
-/**
- * @name HCFG register bit definitions
- * @{
- */
-#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */
-#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select
- mask. */
-#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at
- 48 MHz. */
-#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at
- 6 MHz. */
-/** @} */
-
-/**
- * @name HFIR register bit definitions
- * @{
- */
-#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */
-#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */
-/** @} */
-
-/**
- * @name HFNUM register bit definitions
- * @{
- */
-#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/
-#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/
-#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */
-#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */
-/** @} */
-
-/**
- * @name HPTXSTS register bit definitions
- * @{
- */
-#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic
- transmit request queue
- mask. */
-#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic
- transmit request queue
- value. */
-#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request
- queue Space Available
- mask. */
-#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request
- queue Space Available
- value. */
-#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data
- FIFO Space Available
- mask. */
-#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data
- FIFO Space Available
- value. */
-/** @} */
-
-/**
- * @name HAINT register bit definitions
- * @{
- */
-#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */
-#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */
-/** @} */
-
-/**
- * @name HAINTMSK register bit definitions
- * @{
- */
-#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask
- mask. */
-#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask
- value. */
-/** @} */
-
-/**
- * @name HPRT register bit definitions
- * @{
- */
-#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */
-#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */
-#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */
-#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */
-#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */
-#define HPRT_PPWR (1U<<12) /**< Port power. */
-#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */
-#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */
-#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */
-#define HPRT_PRST (1U<<8) /**< Port reset. */
-#define HPRT_PSUSP (1U<<7) /**< Port suspend. */
-#define HPRT_PRES (1U<<6) /**< Port Resume. */
-#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */
-#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */
-#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/
-#define HPRT_PENA (1U<<2) /**< Port enable. */
-#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */
-#define HPRT_PCSTS (1U<<0) /**< Port connect status. */
-/** @} */
-
-/**
- * @name HCCHAR register bit definitions
- * @{
- */
-#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */
-#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */
-#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */
-#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */
-#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */
-#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */
-#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */
-#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
-#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */
-#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */
-#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/
-#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */
-#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */
-#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */
-#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */
-#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */
-#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */
-#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */
-#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */
-/** @} */
-
-/**
- * @name HCINT register bit definitions
- * @{
- */
-#define HCINT_DTERR (1U<<10) /**< Data toggle error. */
-#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */
-#define HCINT_BBERR (1U<<8) /**< Babble error. */
-#define HCINT_TRERR (1U<<7) /**< Transaction Error. */
-#define HCINT_ACK (1U<<5) /**< ACK response
- received/transmitted
- interrupt. */
-#define HCINT_NAK (1U<<4) /**< NAK response received
- interrupt. */
-#define HCINT_STALL (1U<<3) /**< STALL response received
- interrupt. */
-#define HCINT_CHH (1U<<1) /**< Channel halted. */
-#define HCINT_XFRC (1U<<0) /**< Transfer completed. */
-/** @} */
-
-/**
- * @name HCINTMSK register bit definitions
- * @{
- */
-#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */
-#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */
-#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */
-#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */
-#define HCINTMSK_NYET (1U<<6) /**< NYET response received
- interrupt mask. */
-#define HCINTMSK_ACKM (1U<<5) /**< ACK Response
- received/transmitted
- interrupt mask. */
-#define HCINTMSK_NAKM (1U<<4) /**< NAK response received
- interrupt mask. */
-#define HCINTMSK_STALLM (1U<<3) /**< STALL response received
- interrupt mask. */
-#define HCINTMSK_AHBERRM (1U<<2)
-#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */
-#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */
-/** @} */
-
-/**
- * @name HCTSIZ register bit definitions
- * @{
- */
-#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */
-#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */
-#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */
-#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */
-#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */
-#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */
-#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
-#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */
-#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name DCFG register bit definitions
- * @{
- */
-#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval
- mask. */
-#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval
- value. */
-#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */
-#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */
-#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status
- OUT handshake. */
-#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */
-#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */
-#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS
- mode. */
-#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1
- transceiver clock is 48
- MHz). */
-/** @} */
-
-/**
- * @name DCTL register bit definitions
- * @{
- */
-#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */
-#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */
-#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */
-#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic
- IN NAK. */
-#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic
- IN NAK. */
-#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */
-#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */
-#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */
-#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN
- NAK status. */
-#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */
-#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */
-/** @} */
-
-/**
- * @name DSTS register bit definitions
- * @{
- */
-#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received
- SOF mask. */
-#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received
- SOF value. */
-#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received
- SOF value. */
-#define DSTS_EERR (1U<<3) /**< Erratic error. */
-#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */
-#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is
- running at 48 MHz). */
-#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */
-#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */
-/** @} */
-
-/**
- * @name DIEPMSK register bit definitions
- * @{
- */
-#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */
-#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective
- mask. */
-#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when
- TxFIFO empty mask. */
-#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */
-#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled
- interrupt mask. */
-#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed
- interrupt mask. */
-/** @} */
-
-/**
- * @name DOEPMSK register bit definitions
- * @{
- */
-#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when
- endpoint disabled mask. */
-#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */
-#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled
- interrupt mask. */
-#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed
- interrupt mask. */
-/** @} */
-
-/**
- * @name DAINT register bit definitions
- * @{
- */
-#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt
- bits mask. */
-#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt
- bits value. */
-#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt
- bits mask. */
-#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt
- bits value. */
-/** @} */
-
-/**
- * @name DAINTMSK register bit definitions
- * @{
- */
-#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask
- bits mask. */
-#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask
- bits value. */
-#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask
- bits mask. */
-#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask
- bits value. */
-/** @} */
-
-/**
- * @name DVBUSDIS register bit definitions
- * @{
- */
-#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge
- time mask. */
-#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge
- time value. */
-/** @} */
-
-/**
- * @name DVBUSPULSE register bit definitions
- * @{
- */
-#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time
- mask. */
-#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time
- value. */
-/** @} */
-
-/**
- * @name DIEPEMPMSK register bit definitions
- * @{
- */
-#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty
- interrupt mask bit. */
-/** @} */
-
-/**
- * @name DIEPCTL register bit definitions
- * @{
- */
-#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
-#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
-#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
-#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
-#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
-#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
-#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */
-#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */
-#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */
-#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */
-#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */
-#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */
-#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */
-#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
-#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
-#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
-#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
-#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */
-#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
-#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
-#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
-#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
-#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
-/** @} */
-
-/**
- * @name DIEPINT register bit definitions
- * @{
- */
-#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */
-#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */
-#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when
- TxFIFO is empty. */
-#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */
-#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled
- interrupt. */
-#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */
-/** @} */
-
-/**
- * @name DIEPTSIZ register bit definitions
- * @{
- */
-#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */
-#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */
-#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */
-#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
-#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name DTXFSTS register bit definitions.
- * @{
- */
-#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space
- available. */
-/** @} */
-
-/**
- * @name DOEPCTL register bit definitions.
- * @{
- */
-#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */
-#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */
-#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */
-#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */
-#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */
-#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */
-#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */
-#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */
-#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */
-#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */
-#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */
-#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */
-#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */
-#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */
-#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */
-#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */
-#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */
-#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */
-#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */
-#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */
-#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */
-/** @} */
-
-/**
- * @name DOEPINT register bit definitions
- * @{
- */
-#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets
- received. */
-#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when
- endpoint disabled. */
-#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */
-#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled
- interrupt. */
-#define DOEPINT_XFRC (1U<<0) /**< Transfer completed
- interrupt. */
-/** @} */
-
-/**
- * @name DOEPTSIZ register bit definitions
- * @{
- */
-#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */
-#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */
-#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */
-#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */
-#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */
-#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */
-#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */
-#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */
-/** @} */
-
-/**
- * @name PCGCCTL register bit definitions
- * @{
- */
-#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */
-#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */
-#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */
-/** @} */
-
-/**
- * @brief OTG_FS registers block memory address.
- */
-#define OTG_FS_ADDR 0x50000000
-
-/**
- * @brief OTG_HS registers block memory address.
- */
-#define OTG_HS_ADDR 0x40040000
-
-/**
- * @brief Accesses to the OTG_FS registers block.
- */
-#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR)
-
-/**
- * @brief Accesses to the OTG_HS registers block.
- */
-#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR)
-
-#endif /* _STM32_OTG_H_ */
-
-/** @} */
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/** + * @file stm32_otg.h + * @brief STM32 OTG registers layout header. + * + * @addtogroup USB + * @{ + */ + + +#ifndef _STM32_OTG_H_ +#define _STM32_OTG_H_ + +/** + * @brief Number of the implemented endpoints in OTG_FS. + * @details This value does not include the endpoint 0 that is always present. + */ +#define STM32_OTG1_ENDOPOINTS_NUMBER 3 + +/** + * @brief Number of the implemented endpoints in OTG_HS. + * @details This value does not include the endpoint 0 that is always present. + */ +#define STM32_OTG2_ENDOPOINTS_NUMBER 5 + +/** + * @brief OTG_FS FIFO memory size in words. + */ +#define STM32_OTG1_FIFO_MEM_SIZE 320 + +/** + * @brief OTG_HS FIFO memory size in words. + */ +#define STM32_OTG2_FIFO_MEM_SIZE 1024 + +/** + * @brief Host channel registers group. + */ +typedef struct { + volatile uint32_t HCCHAR; /**< @brief Host channel characteristics + register. */ + volatile uint32_t resvd8; + volatile uint32_t HCINT; /**< @brief Host channel interrupt register.*/ + volatile uint32_t HCINTMSK; /**< @brief Host channel interrupt mask + register. */ + volatile uint32_t HCTSIZ; /**< @brief Host channel transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1c; +} stm32_otg_host_chn_t; + +/** + * @brief Device input endpoint registers group. + */ +typedef struct { + volatile uint32_t DIEPCTL; /**< @brief Device control IN endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DIEPINT; /**< @brief Device IN endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DIEPTSIZ; /**< @brief Device IN endpoint transfer size + register. */ + volatile uint32_t resvd14; + volatile uint32_t DTXFSTS; /**< @brief Device IN endpoint transmit FIFO + status register. */ + volatile uint32_t resvd1C; +} stm32_otg_in_ep_t; + +/** + * @brief Device output endpoint registers group. + */ +typedef struct { + volatile uint32_t DOEPCTL; /**< @brief Device control OUT endpoint + control register. */ + volatile uint32_t resvd4; + volatile uint32_t DOEPINT; /**< @brief Device OUT endpoint interrupt + register. */ + volatile uint32_t resvdC; + volatile uint32_t DOEPTSIZ; /**< @brief Device OUT endpoint transfer + size register. */ + volatile uint32_t resvd14; + volatile uint32_t resvd18; + volatile uint32_t resvd1C; +} stm32_otg_out_ep_t; + +/** + * @brief USB registers memory map. + */ +typedef struct { + volatile uint32_t GOTGCTL; /**< @brief OTG control and status register.*/ + volatile uint32_t GOTGINT; /**< @brief OTG interrupt register. */ + volatile uint32_t GAHBCFG; /**< @brief AHB configuration register. */ + volatile uint32_t GUSBCFG; /**< @brief USB configuration register. */ + volatile uint32_t GRSTCTL; /**< @brief Reset register size. */ + volatile uint32_t GINTSTS; /**< @brief Interrupt register. */ + volatile uint32_t GINTMSK; /**< @brief Interrupt mask register. */ + volatile uint32_t GRXSTSR; /**< @brief Receive status debug read + register. */ + volatile uint32_t GRXSTSP; /**< @brief Receive status read/pop + register. */ + volatile uint32_t GRXFSIZ; /**< @brief Receive FIFO size register. */ + volatile uint32_t DIEPTXF0; /**< @brief Endpoint 0 transmit FIFO size + register. */ + volatile uint32_t HNPTXSTS; /**< @brief Non-periodic transmit FIFO/queue + status register. */ + volatile uint32_t resvd30; + volatile uint32_t resvd34; + volatile uint32_t GCCFG; /**< @brief General core configuration. */ + volatile uint32_t CID; /**< @brief Core ID register. */ + volatile uint32_t resvd58[48]; + volatile uint32_t HPTXFSIZ; /**< @brief Host periodic transmit FIFO size + register. */ + volatile uint32_t DIEPTXF[15];/**< @brief Device IN endpoint transmit FIFO + size registers. */ + volatile uint32_t resvd140[176]; + volatile uint32_t HCFG; /**< @brief Host configuration register. */ + volatile uint32_t HFIR; /**< @brief Host frame interval register. */ + volatile uint32_t HFNUM; /**< @brief Host frame number/frame time + Remaining register. */ + volatile uint32_t resvd40C; + volatile uint32_t HPTXSTS; /**< @brief Host periodic transmit FIFO/queue + status register. */ + volatile uint32_t HAINT; /**< @brief Host all channels interrupt + register. */ + volatile uint32_t HAINTMSK; /**< @brief Host all channels interrupt mask + register. */ + volatile uint32_t resvd41C[9]; + volatile uint32_t HPRT; /**< @brief Host port control and status + register. */ + volatile uint32_t resvd444[47]; + stm32_otg_host_chn_t hc[16]; /**< @brief Host channels array. */ + volatile uint32_t resvd700[64]; + volatile uint32_t DCFG; /**< @brief Device configuration register. */ + volatile uint32_t DCTL; /**< @brief Device control register. */ + volatile uint32_t DSTS; /**< @brief Device status register. */ + volatile uint32_t resvd80C; + volatile uint32_t DIEPMSK; /**< @brief Device IN endpoint common + interrupt mask register. */ + volatile uint32_t DOEPMSK; /**< @brief Device OUT endpoint common + interrupt mask register. */ + volatile uint32_t DAINT; /**< @brief Device all endpoints interrupt + register. */ + volatile uint32_t DAINTMSK; /**< @brief Device all endpoints interrupt + mask register. */ + volatile uint32_t resvd820; + volatile uint32_t resvd824; + volatile uint32_t DVBUSDIS; /**< @brief Device VBUS discharge time + register. */ + volatile uint32_t DVBUSPULSE; /**< @brief Device VBUS pulsing time + register. */ + volatile uint32_t resvd830; + volatile uint32_t DIEPEMPMSK; /**< @brief Device IN endpoint FIFO empty + interrupt mask register. */ + volatile uint32_t resvd838; + volatile uint32_t resvd83C; + volatile uint32_t resvd840[16]; + volatile uint32_t resvd880[16]; + volatile uint32_t resvd8C0[16]; + stm32_otg_in_ep_t ie[16]; /**< @brief Input endpoints. */ + stm32_otg_out_ep_t oe[16]; /**< @brief Output endpoints. */ + volatile uint32_t resvdD00[64]; + volatile uint32_t PCGCCTL; /**< @brief Power and clock gating control + register. */ + volatile uint32_t resvdE04[127]; + volatile uint32_t FIFO[16][1024]; +} stm32_otg_t; + +/** + * @name GOTGCTL register bit definitions + * @{ + */ +#define GOTGCTL_BSVLD (1U<<19) /**< B-Session Valid. */ +#define GOTGCTL_ASVLD (1U<<18) /**< A-Session Valid. */ +#define GOTGCTL_DBCT (1U<<17) /**< Long/Short debounce time. */ +#define GOTGCTL_CIDSTS (1U<<16) /**< Connector ID status. */ +#define GOTGCTL_EHEN (1U<<12) +#define GOTGCTL_DHNPEN (1U<<11) /**< Device HNP enabled. */ +#define GOTGCTL_HSHNPEN (1U<<10) /**< Host Set HNP enable. */ +#define GOTGCTL_HNPRQ (1U<<9) /**< HNP request. */ +#define GOTGCTL_HNGSCS (1U<<8) /**< Host negotiation success. */ +#define GOTGCTL_BVALOVAL (1U<<7) +#define GOTGCTL_BVALOEN (1U<<6) +#define GOTGCTL_AVALOVAL (1U<<5) +#define GOTGCTL_AVALOEN (1U<<4) +#define GOTGCTL_VBVALOVAL (1U<<3) +#define GOTGCTL_VBVALOEN (1U<<2) +#define GOTGCTL_SRQ (1U<<1) /**< Session request. */ +#define GOTGCTL_SRQSCS (1U<<0) /**< Session request success. */ +/** @} */ + +/** + * @name GOTGINT register bit definitions + * @{ + */ +#define GOTGINT_DBCDNE (1U<<19) /**< Debounce done. */ +#define GOTGINT_ADTOCHG (1U<<18) /**< A-Device timeout change. */ +#define GOTGINT_HNGDET (1U<<17) /**< Host negotiation detected. */ +#define GOTGINT_HNSSCHG (1U<<9) /**< Host negotiation success + status change. */ +#define GOTGINT_SRSSCHG (1U<<8) /**< Session request success + status change. */ +#define GOTGINT_SEDET (1U<<2) /**< Session end detected. */ +/** @} */ + +/** + * @name GAHBCFG register bit definitions + * @{ + */ +#define GAHBCFG_PTXFELVL (1U<<8) /**< Periodic TxFIFO empty + level. */ +#define GAHBCFG_TXFELVL (1U<<7) /**< Non-periodic TxFIFO empty + level. */ +#define GAHBCFG_DMAEN (1U<<5) /**< DMA enable (HS only). */ +#define GAHBCFG_HBSTLEN_MASK (15U<<1) /**< Burst length/type mask (HS + only). */ +#define GAHBCFG_HBSTLEN(n) ((n)<<1) /**< Burst length/type (HS + only). */ +#define GAHBCFG_GINTMSK (1U<<0) /**< Global interrupt mask. */ +/** @} */ + +/** + * @name GUSBCFG register bit definitions + * @{ + */ +#define GUSBCFG_CTXPKT (1U<<31) /**< Corrupt Tx packet. */ +#define GUSBCFG_FDMOD (1U<<30) /**< Force Device Mode. */ +#define GUSBCFG_FHMOD (1U<<29) /**< Force Host Mode. */ +#define GUSBCFG_TRDT_MASK (15U<<10) /**< USB Turnaround time field + mask. */ +#define GUSBCFG_TRDT(n) ((n)<<10) /**< USB Turnaround time field + value. */ +#define GUSBCFG_HNPCAP (1U<<9) /**< HNP-Capable. */ +#define GUSBCFG_SRPCAP (1U<<8) /**< SRP-Capable. */ +#define GUSBCFG_PHYSEL (1U<<6) /**< USB 2.0 High-Speed PHY or + USB 1.1 Full-Speed serial + transceiver Select. */ +#define GUSBCFG_TOCAL_MASK (7U<<0) /**< HS/FS timeout calibration + field mask. */ +#define GUSBCFG_TOCAL(n) ((n)<<0) /**< HS/FS timeout calibration + field value. */ +/** @} */ + +/** + * @name GRSTCTL register bit definitions + * @{ + */ +#define GRSTCTL_AHBIDL (1U<<31) /**< AHB Master Idle. */ +#define GRSTCTL_TXFNUM_MASK (31U<<6) /**< TxFIFO number field mask. */ +#define GRSTCTL_TXFNUM(n) ((n)<<6) /**< TxFIFO number field value. */ +#define GRSTCTL_TXFFLSH (1U<<5) /**< TxFIFO flush. */ +#define GRSTCTL_RXFFLSH (1U<<4) /**< RxFIFO flush. */ +#define GRSTCTL_FCRST (1U<<2) /**< Host frame counter reset. */ +#define GRSTCTL_HSRST (1U<<1) /**< HClk soft reset. */ +#define GRSTCTL_CSRST (1U<<0) /**< Core soft reset. */ +/** @} */ + +/** + * @name GINTSTS register bit definitions + * @{ + */ +#define GINTSTS_WKUPINT (1U<<31) /**< Resume/Remote wakeup + detected interrupt. */ +#define GINTSTS_SRQINT (1U<<30) /**< Session request/New session + detected interrupt. */ +#define GINTSTS_DISCINT (1U<<29) /**< Disconnect detected + interrupt. */ +#define GINTSTS_CIDSCHG (1U<<28) /**< Connector ID status change.*/ +#define GINTSTS_PTXFE (1U<<26) /**< Periodic TxFIFO empty. */ +#define GINTSTS_HCINT (1U<<25) /**< Host channels interrupt. */ +#define GINTSTS_HPRTINT (1U<<24) /**< Host port interrupt. */ +#define GINTSTS_IPXFR (1U<<21) /**< Incomplete periodic + transfer. */ +#define GINTSTS_IISOOXFR (1U<<21) /**< Incomplete isochronous OUT + transfer. */ +#define GINTSTS_IISOIXFR (1U<<20) /**< Incomplete isochronous IN + transfer. */ +#define GINTSTS_OEPINT (1U<<19) /**< OUT endpoints interrupt. */ +#define GINTSTS_IEPINT (1U<<18) /**< IN endpoints interrupt. */ +#define GINTSTS_EOPF (1U<<15) /**< End of periodic frame + interrupt. */ +#define GINTSTS_ISOODRP (1U<<14) /**< Isochronous OUT packet + dropped interrupt. */ +#define GINTSTS_ENUMDNE (1U<<13) /**< Enumeration done. */ +#define GINTSTS_USBRST (1U<<12) /**< USB reset. */ +#define GINTSTS_USBSUSP (1U<<11) /**< USB suspend. */ +#define GINTSTS_ESUSP (1U<<10) /**< Early suspend. */ +#define GINTSTS_GONAKEFF (1U<<7) /**< Global OUT NAK effective. */ +#define GINTSTS_GINAKEFF (1U<<6) /**< Global IN non-periodic NAK + effective. */ +#define GINTSTS_NPTXFE (1U<<5) /**< Non-periodic TxFIFO empty. */ +#define GINTSTS_RXFLVL (1U<<4) /**< RxFIFO non-empty. */ +#define GINTSTS_SOF (1U<<3) /**< Start of frame. */ +#define GINTSTS_OTGINT (1U<<2) /**< OTG interrupt. */ +#define GINTSTS_MMIS (1U<<1) /**< Mode Mismatch interrupt. */ +#define GINTSTS_CMOD (1U<<0) /**< Current mode of operation. */ +/** @} */ + +/** + * @name GINTMSK register bit definitions + * @{ + */ +#define GINTMSK_WKUM (1U<<31) /**< Resume/remote wakeup + detected interrupt mask. */ +#define GINTMSK_SRQM (1U<<30) /**< Session request/New session + detected interrupt mask. */ +#define GINTMSK_DISCM (1U<<29) /**< Disconnect detected + interrupt mask. */ +#define GINTMSK_CIDSCHGM (1U<<28) /**< Connector ID status change + mask. */ +#define GINTMSK_PTXFEM (1U<<26) /**< Periodic TxFIFO empty mask.*/ +#define GINTMSK_HCM (1U<<25) /**< Host channels interrupt + mask. */ +#define GINTMSK_HPRTM (1U<<24) /**< Host port interrupt mask. */ +#define GINTMSK_IPXFRM (1U<<21) /**< Incomplete periodic + transfer mask. */ +#define GINTMSK_IISOOXFRM (1U<<21) /**< Incomplete isochronous OUT + transfer mask. */ +#define GINTMSK_IISOIXFRM (1U<<20) /**< Incomplete isochronous IN + transfer mask. */ +#define GINTMSK_OEPM (1U<<19) /**< OUT endpoints interrupt + mask. */ +#define GINTMSK_IEPM (1U<<18) /**< IN endpoints interrupt + mask. */ +#define GINTMSK_EOPFM (1U<<15) /**< End of periodic frame + interrupt mask. */ +#define GINTMSK_ISOODRPM (1U<<14) /**< Isochronous OUT packet + dropped interrupt mask. */ +#define GINTMSK_ENUMDNEM (1U<<13) /**< Enumeration done mask. */ +#define GINTMSK_USBRSTM (1U<<12) /**< USB reset mask. */ +#define GINTMSK_USBSUSPM (1U<<11) /**< USB suspend mask. */ +#define GINTMSK_ESUSPM (1U<<10) /**< Early suspend mask. */ +#define GINTMSK_GONAKEFFM (1U<<7) /**< Global OUT NAK effective + mask. */ +#define GINTMSK_GINAKEFFM (1U<<6) /**< Global non-periodic IN NAK + effective mask. */ +#define GINTMSK_NPTXFEM (1U<<5) /**< Non-periodic TxFIFO empty + mask. */ +#define GINTMSK_RXFLVLM (1U<<4) /**< Receive FIFO non-empty + mask. */ +#define GINTMSK_SOFM (1U<<3) /**< Start of (micro)frame mask.*/ +#define GINTMSK_OTGM (1U<<2) /**< OTG interrupt mask. */ +#define GINTMSK_MMISM (1U<<1) /**< Mode Mismatch interrupt + mask. */ +/** @} */ + +/** + * @name GRXSTSR register bit definitions + * @{ + */ +#define GRXSTSR_PKTSTS_MASK (15U<<17) /**< Packet status mask. */ +#define GRXSTSR_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSR_OUT_GLOBAL_NAK GRXSTSR_PKTSTS(1) +#define GRXSTSR_OUT_DATA GRXSTSR_PKTSTS(2) +#define GRXSTSR_OUT_COMP GRXSTSR_PKTSTS(3) +#define GRXSTSR_SETUP_COMP GRXSTSR_PKTSTS(4) +#define GRXSTSR_SETUP_DATA GRXSTSR_PKTSTS(6) +#define GRXSTSR_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSR_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSR_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSR_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSR_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSR_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSR_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSR_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXSTSP register bit definitions + * @{ + */ +#define GRXSTSP_PKTSTS_MASK (15<<17) /**< Packet status mask. */ +#define GRXSTSP_PKTSTS(n) ((n)<<17) /**< Packet status value. */ +#define GRXSTSP_OUT_GLOBAL_NAK GRXSTSP_PKTSTS(1) +#define GRXSTSP_OUT_DATA GRXSTSP_PKTSTS(2) +#define GRXSTSP_OUT_COMP GRXSTSP_PKTSTS(3) +#define GRXSTSP_SETUP_COMP GRXSTSP_PKTSTS(4) +#define GRXSTSP_SETUP_DATA GRXSTSP_PKTSTS(6) +#define GRXSTSP_DPID_MASK (3U<<15) /**< Data PID mask. */ +#define GRXSTSP_DPID(n) ((n)<<15) /**< Data PID value. */ +#define GRXSTSP_BCNT_MASK (0x7FF<<4) /**< Byte count mask. */ +#define GRXSTSP_BCNT_OFF 4 /**< Byte count offset. */ +#define GRXSTSP_BCNT(n) ((n)<<4) /**< Byte count value. */ +#define GRXSTSP_CHNUM_MASK (15U<<0) /**< Channel number mask. */ +#define GRXSTSP_CHNUM(n) ((n)<<0) /**< Channel number value. */ +#define GRXSTSP_EPNUM_MASK (15U<<0) /**< Endpoint number mask. */ +#define GRXSTSP_EPNUM_OFF 0 /**< Endpoint number offset. */ +#define GRXSTSP_EPNUM(n) ((n)<<0) /**< Endpoint number value. */ +/** @} */ + +/** + * @name GRXFSIZ register bit definitions + * @{ + */ +#define GRXFSIZ_RXFD_MASK (0xFFFF<<0) /**< RxFIFO depth mask. */ +#define GRXFSIZ_RXFD(n) ((n)<<0) /**< RxFIFO depth value. */ +/** @} */ + +/** + * @name DIEPTXFx register bit definitions + * @{ + */ +#define DIEPTXF_INEPTXFD_MASK (0xFFFFU<<16)/**< IN endpoint TxFIFO depth + mask. */ +#define DIEPTXF_INEPTXFD(n) ((n)<<16) /**< IN endpoint TxFIFO depth + value. */ +#define DIEPTXF_INEPTXSA_MASK (0xFFFF<<0) /**< IN endpoint FIFOx transmit + RAM start address mask. */ +#define DIEPTXF_INEPTXSA(n) ((n)<<0) /**< IN endpoint FIFOx transmit + RAM start address value. */ +/** @} */ + +/** + * @name GCCFG register bit definitions + * @{ + */ +#define GCCFG_NOVBUSSENS (1U<<21) /**< VBUS sensing disable. */ +#define GCCFG_SOFOUTEN (1U<<20) /**< SOF output enable. */ +#define GCCFG_VBUSBSEN (1U<<19) /**< Enable the VBUS sensing "B" + device. */ +#define GCCFG_VBUSASEN (1U<<18) /**< Enable the VBUS sensing "A" + device. */ +#define GCCFG_PWRDWN (1U<<16) /**< Power down. */ +/** @} */ + +/** + * @name HPTXFSIZ register bit definitions + * @{ + */ +#define HPTXFSIZ_PTXFD_MASK (0xFFFFU<<16)/**< Host periodic TxFIFO + depth mask. */ +#define HPTXFSIZ_PTXFD(n) ((n)<<16) /**< Host periodic TxFIFO + depth value. */ +#define HPTXFSIZ_PTXSA_MASK (0xFFFFU<<0)/**< Host periodic TxFIFO + Start address mask. */ +#define HPTXFSIZ_PTXSA(n) ((n)<<0) /**< Host periodic TxFIFO + start address value. */ +/** @} */ + +/** + * @name HCFG register bit definitions + * @{ + */ +#define HCFG_FSLSS (1U<<2) /**< FS- and LS-only support. */ +#define HCFG_FSLSPCS_MASK (3U<<0) /**< FS/LS PHY clock select + mask. */ +#define HCFG_FSLSPCS_48 (1U<<0) /**< PHY clock is running at + 48 MHz. */ +#define HCFG_FSLSPCS_6 (2U<<0) /**< PHY clock is running at + 6 MHz. */ +/** @} */ + +/** + * @name HFIR register bit definitions + * @{ + */ +#define HFIR_FRIVL_MASK (0xFFFFU<<0)/**< Frame interval mask. */ +#define HFIR_FRIVL(n) ((n)<<0) /**< Frame interval value. */ +/** @} */ + +/** + * @name HFNUM register bit definitions + * @{ + */ +#define HFNUM_FTREM_MASK (0xFFFFU<<16)/**< Frame time Remaining mask.*/ +#define HFNUM_FTREM(n) ((n)<<16) /**< Frame time Remaining value.*/ +#define HFNUM_FRNUM_MASK (0xFFFFU<<0)/**< Frame number mask. */ +#define HFNUM_FRNUM(n) ((n)<<0) /**< Frame number value. */ +/** @} */ + +/** + * @name HPTXSTS register bit definitions + * @{ + */ +#define HPTXSTS_PTXQTOP_MASK (0xFFU<<24) /**< Top of the periodic + transmit request queue + mask. */ +#define HPTXSTS_PTXQTOP(n) ((n)<<24) /**< Top of the periodic + transmit request queue + value. */ +#define HPTXSTS_PTXQSAV_MASK (0xFF<<16) /**< Periodic transmit request + queue Space Available + mask. */ +#define HPTXSTS_PTXQSAV(n) ((n)<<16) /**< Periodic transmit request + queue Space Available + value. */ +#define HPTXSTS_PTXFSAVL_MASK (0xFFFF<<0) /**< Periodic transmit Data + FIFO Space Available + mask. */ +#define HPTXSTS_PTXFSAVL(n) ((n)<<0) /**< Periodic transmit Data + FIFO Space Available + value. */ +/** @} */ + +/** + * @name HAINT register bit definitions + * @{ + */ +#define HAINT_HAINT_MASK (0xFFFFU<<0)/**< Channel interrupts mask. */ +#define HAINT_HAINT(n) ((n)<<0) /**< Channel interrupts value. */ +/** @} */ + +/** + * @name HAINTMSK register bit definitions + * @{ + */ +#define HAINTMSK_HAINTM_MASK (0xFFFFU<<0)/**< Channel interrupt mask + mask. */ +#define HAINTMSK_HAINTM(n) ((n)<<0) /**< Channel interrupt mask + value. */ +/** @} */ + +/** + * @name HPRT register bit definitions + * @{ + */ +#define HPRT_PSPD_MASK (3U<<17) /**< Port speed mask. */ +#define HPRT_PSPD_FS (1U<<17) /**< Full speed value. */ +#define HPRT_PSPD_LS (2U<<17) /**< Low speed value. */ +#define HPRT_PTCTL_MASK (15<<13) /**< Port Test control mask. */ +#define HPRT_PTCTL(n) ((n)<<13) /**< Port Test control value. */ +#define HPRT_PPWR (1U<<12) /**< Port power. */ +#define HPRT_PLSTS_MASK (3U<<11) /**< Port Line status mask. */ +#define HPRT_PLSTS_DM (1U<<11) /**< Logic level of D-. */ +#define HPRT_PLSTS_DP (1U<<10) /**< Logic level of D+. */ +#define HPRT_PRST (1U<<8) /**< Port reset. */ +#define HPRT_PSUSP (1U<<7) /**< Port suspend. */ +#define HPRT_PRES (1U<<6) /**< Port Resume. */ +#define HPRT_POCCHNG (1U<<5) /**< Port overcurrent change. */ +#define HPRT_POCA (1U<<4) /**< Port overcurrent active. */ +#define HPRT_PENCHNG (1U<<3) /**< Port enable/disable change.*/ +#define HPRT_PENA (1U<<2) /**< Port enable. */ +#define HPRT_PCDET (1U<<1) /**< Port Connect detected. */ +#define HPRT_PCSTS (1U<<0) /**< Port connect status. */ +/** @} */ + +/** + * @name HCCHAR register bit definitions + * @{ + */ +#define HCCHAR_CHENA (1U<<31) /**< Channel enable. */ +#define HCCHAR_CHDIS (1U<<30) /**< Channel Disable. */ +#define HCCHAR_ODDFRM (1U<<29) /**< Odd frame. */ +#define HCCHAR_DAD_MASK (0x7FU<<22) /**< Device Address mask. */ +#define HCCHAR_DAD(n) ((n)<<22) /**< Device Address value. */ +#define HCCHAR_MCNT_MASK (3U<<20) /**< Multicount mask. */ +#define HCCHAR_MCNT(n) ((n)<<20) /**< Multicount value. */ +#define HCCHAR_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define HCCHAR_EPTYP(n) ((n)<<18) /**< Endpoint type value. */ +#define HCCHAR_EPTYP_CTL (0U<<18) /**< Control endpoint value. */ +#define HCCHAR_EPTYP_ISO (1U<<18) /**< Isochronous endpoint value.*/ +#define HCCHAR_EPTYP_BULK (2U<<18) /**< Bulk endpoint value. */ +#define HCCHAR_EPTYP_INTR (3U<<18) /**< Interrupt endpoint value. */ +#define HCCHAR_LSDEV (1U<<17) /**< Low-Speed device. */ +#define HCCHAR_EPDIR (1U<<15) /**< Endpoint direction. */ +#define HCCHAR_EPNUM_MASK (15U<<11) /**< Endpoint number mask. */ +#define HCCHAR_EPNUM(n) ((n)<<11) /**< Endpoint number value. */ +#define HCCHAR_MPS_MASK (0x7FFU<<0) /**< Maximum packet size mask. */ +#define HCCHAR_MPS(n) ((n)<<0) /**< Maximum packet size value. */ +/** @} */ + +/** + * @name HCINT register bit definitions + * @{ + */ +#define HCINT_DTERR (1U<<10) /**< Data toggle error. */ +#define HCINT_FRMOR (1U<<9) /**< Frame overrun. */ +#define HCINT_BBERR (1U<<8) /**< Babble error. */ +#define HCINT_TRERR (1U<<7) /**< Transaction Error. */ +#define HCINT_ACK (1U<<5) /**< ACK response + received/transmitted + interrupt. */ +#define HCINT_NAK (1U<<4) /**< NAK response received + interrupt. */ +#define HCINT_STALL (1U<<3) /**< STALL response received + interrupt. */ +#define HCINT_CHH (1U<<1) /**< Channel halted. */ +#define HCINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name HCINTMSK register bit definitions + * @{ + */ +#define HCINTMSK_DTERRM (1U<<10) /**< Data toggle error mask. */ +#define HCINTMSK_FRMORM (1U<<9) /**< Frame overrun mask. */ +#define HCINTMSK_BBERRM (1U<<8) /**< Babble error mask. */ +#define HCINTMSK_TRERRM (1U<<7) /**< Transaction error mask. */ +#define HCINTMSK_NYET (1U<<6) /**< NYET response received + interrupt mask. */ +#define HCINTMSK_ACKM (1U<<5) /**< ACK Response + received/transmitted + interrupt mask. */ +#define HCINTMSK_NAKM (1U<<4) /**< NAK response received + interrupt mask. */ +#define HCINTMSK_STALLM (1U<<3) /**< STALL response received + interrupt mask. */ +#define HCINTMSK_AHBERRM (1U<<2) +#define HCINTMSK_CHHM (1U<<1) /**< Channel halted mask. */ +#define HCINTMSK_XFRCM (1U<<0) /**< Transfer completed mask. */ +/** @} */ + +/** + * @name HCTSIZ register bit definitions + * @{ + */ +#define HCTSIZ_DPID_MASK (3U<<29) /**< PID mask. */ +#define HCTSIZ_DPID_DATA0 (0U<<29) /**< DATA0. */ +#define HCTSIZ_DPID_DATA2 (1U<<29) /**< DATA2. */ +#define HCTSIZ_DPID_DATA1 (2U<<29) /**< DATA1. */ +#define HCTSIZ_DPID_MDATA (3U<<29) /**< MDATA. */ +#define HCTSIZ_DPID_SETUP (3U<<29) /**< SETUP. */ +#define HCTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define HCTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define HCTSIZ_XFRSIZ_MASK (0x7FFFF<<0)/**< Transfer size mask. */ +#define HCTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DCFG register bit definitions + * @{ + */ +#define DCFG_PFIVL_MASK (3U<<11) /**< Periodic frame interval + mask. */ +#define DCFG_PFIVL(n) ((n)<<11) /**< Periodic frame interval + value. */ +#define DCFG_DAD_MASK (0x7FU<<4) /**< Device address mask. */ +#define DCFG_DAD(n) ((n)<<4) /**< Device address value. */ +#define DCFG_NZLSOHSK (1U<<2) /**< Non-Zero-Length status + OUT handshake. */ +#define DCFG_DSPD_MASK (3U<<0) /**< Device speed mask. */ +#define DCFG_DSPD_HS (0U<<0) /**< High speed (USB 2.0). */ +#define DCFG_DSPD_HS_FS (1U<<0) /**< High speed (USB 2.0) in FS + mode. */ +#define DCFG_DSPD_FS11 (3U<<0) /**< Full speed (USB 1.1 + transceiver clock is 48 + MHz). */ +/** @} */ + +/** + * @name DCTL register bit definitions + * @{ + */ +#define DCTL_POPRGDNE (1U<<11) /**< Power-on programming done. */ +#define DCTL_CGONAK (1U<<10) /**< Clear global OUT NAK. */ +#define DCTL_SGONAK (1U<<9) /**< Set global OUT NAK. */ +#define DCTL_CGINAK (1U<<8) /**< Clear global non-periodic + IN NAK. */ +#define DCTL_SGINAK (1U<<7) /**< Set global non-periodic + IN NAK. */ +#define DCTL_TCTL_MASK (7U<<4) /**< Test control mask. */ +#define DCTL_TCTL(n) ((n)<<4 /**< Test control value. */ +#define DCTL_GONSTS (1U<<3) /**< Global OUT NAK status. */ +#define DCTL_GINSTS (1U<<2) /**< Global non-periodic IN + NAK status. */ +#define DCTL_SDIS (1U<<1) /**< Soft disconnect. */ +#define DCTL_RWUSIG (1U<<0) /**< Remote wakeup signaling. */ +/** @} */ + +/** + * @name DSTS register bit definitions + * @{ + */ +#define DSTS_FNSOF_MASK (0x3FFU<<8) /**< Frame number of the received + SOF mask. */ +#define DSTS_FNSOF(n) ((n)<<8) /**< Frame number of the received + SOF value. */ +#define DSTS_FNSOF_ODD (1U<<8) /**< Frame parity of the received + SOF value. */ +#define DSTS_EERR (1U<<3) /**< Erratic error. */ +#define DSTS_ENUMSPD_MASK (3U<<1) /**< Enumerated speed mask. */ +#define DSTS_ENUMSPD_FS_48 (3U<<1) /**< Full speed (PHY clock is + running at 48 MHz). */ +#define DSTS_ENUMSPD_HS_480 (0U<<1) /**< High speed. */ +#define DSTS_SUSPSTS (1U<<0) /**< Suspend status. */ +/** @} */ + +/** + * @name DIEPMSK register bit definitions + * @{ + */ +#define DIEPMSK_TXFEM (1U<<6) /**< Transmit FIFO empty mask. */ +#define DIEPMSK_INEPNEM (1U<<6) /**< IN endpoint NAK effective + mask. */ +#define DIEPMSK_ITTXFEMSK (1U<<4) /**< IN token received when + TxFIFO empty mask. */ +#define DIEPMSK_TOCM (1U<<3) /**< Timeout condition mask. */ +#define DIEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DIEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DOEPMSK register bit definitions + * @{ + */ +#define DOEPMSK_OTEPDM (1U<<4) /**< OUT token received when + endpoint disabled mask. */ +#define DOEPMSK_STUPM (1U<<3) /**< SETUP phase done mask. */ +#define DOEPMSK_EPDM (1U<<1) /**< Endpoint disabled + interrupt mask. */ +#define DOEPMSK_XFRCM (1U<<0) /**< Transfer completed + interrupt mask. */ +/** @} */ + +/** + * @name DAINT register bit definitions + * @{ + */ +#define DAINT_OEPINT_MASK (0xFFFFU<<16)/**< OUT endpoint interrupt + bits mask. */ +#define DAINT_OEPINT(n) ((n)<<16) /**< OUT endpoint interrupt + bits value. */ +#define DAINT_IEPINT_MASK (0xFFFFU<<0)/**< IN endpoint interrupt + bits mask. */ +#define DAINT_IEPINT(n) ((n)<<0) /**< IN endpoint interrupt + bits value. */ +/** @} */ + +/** + * @name DAINTMSK register bit definitions + * @{ + */ +#define DAINTMSK_OEPM_MASK (0xFFFFU<<16)/**< OUT EP interrupt mask + bits mask. */ +#define DAINTMSK_OEPM(n) (1U<<(16+(n)))/**< OUT EP interrupt mask + bits value. */ +#define DAINTMSK_IEPM_MASK (0xFFFFU<<0)/**< IN EP interrupt mask + bits mask. */ +#define DAINTMSK_IEPM(n) (1U<<(n)) /**< IN EP interrupt mask + bits value. */ +/** @} */ + +/** + * @name DVBUSDIS register bit definitions + * @{ + */ +#define DVBUSDIS_VBUSDT_MASK (0xFFFFU<<0)/**< Device VBUS discharge + time mask. */ +#define DVBUSDIS_VBUSDT(n) ((n)<<0) /**< Device VBUS discharge + time value. */ +/** @} */ + +/** + * @name DVBUSPULSE register bit definitions + * @{ + */ +#define DVBUSPULSE_DVBUSP_MASK (0xFFFU<<0) /**< Device VBUSpulsing time + mask. */ +#define DVBUSPULSE_DVBUSP(n) ((n)<<0) /**< Device VBUS pulsing time + value. */ +/** @} */ + +/** + * @name DIEPEMPMSK register bit definitions + * @{ + */ +#define DIEPEMPMSK_INEPTXFEM(n) (1U<<(n)) /**< IN EP Tx FIFO empty + interrupt mask bit. */ +/** @} */ + +/** + * @name DIEPCTL register bit definitions + * @{ + */ +#define DIEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DIEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DIEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DIEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DIEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DIEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DIEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DIEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DIEPCTL_TXFNUM_MASK (15U<<22) /**< TxFIFO number mask. */ +#define DIEPCTL_TXFNUM(n) ((n)<<22) /**< TxFIFO number value. */ +#define DIEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DIEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DIEPCTL_EPTYP_MASK (3<<18) /**< Endpoint type mask. */ +#define DIEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DIEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DIEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DIEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DIEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DIEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DIEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DIEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DIEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DIEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DIEPINT register bit definitions + * @{ + */ +#define DIEPINT_TXFE (1U<<7) /**< Transmit FIFO empty. */ +#define DIEPINT_INEPNE (1U<<6) /**< IN endpoint NAK effective. */ +#define DIEPINT_ITTXFE (1U<<4) /**< IN Token received when + TxFIFO is empty. */ +#define DIEPINT_TOC (1U<<3) /**< Timeout condition. */ +#define DIEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DIEPINT_XFRC (1U<<0) /**< Transfer completed. */ +/** @} */ + +/** + * @name DIEPTSIZ register bit definitions + * @{ + */ +#define DIEPTSIZ_MCNT_MASK (3U<<29) /**< Multi count mask. */ +#define DIEPTSIZ_MCNT(n) ((n)<<29) /**< Multi count value. */ +#define DIEPTSIZ_PKTCNT_MASK (0x3FF<<19) /**< Packet count mask. */ +#define DIEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DIEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DIEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name DTXFSTS register bit definitions. + * @{ + */ +#define DTXFSTS_INEPTFSAV_MASK (0xFFFF<<0) /**< IN endpoint TxFIFO space + available. */ +/** @} */ + +/** + * @name DOEPCTL register bit definitions. + * @{ + */ +#define DOEPCTL_EPENA (1U<<31) /**< Endpoint enable. */ +#define DOEPCTL_EPDIS (1U<<30) /**< Endpoint disable. */ +#define DOEPCTL_SD1PID (1U<<29) /**< Set DATA1 PID. */ +#define DOEPCTL_SODDFRM (1U<<29) /**< Set odd frame. */ +#define DOEPCTL_SD0PID (1U<<28) /**< Set DATA0 PID. */ +#define DOEPCTL_SEVNFRM (1U<<28) /**< Set even frame. */ +#define DOEPCTL_SNAK (1U<<27) /**< Set NAK. */ +#define DOEPCTL_CNAK (1U<<26) /**< Clear NAK. */ +#define DOEPCTL_STALL (1U<<21) /**< STALL handshake. */ +#define DOEPCTL_SNPM (1U<<20) /**< Snoop mode. */ +#define DOEPCTL_EPTYP_MASK (3U<<18) /**< Endpoint type mask. */ +#define DOEPCTL_EPTYP_CTRL (0U<<18) /**< Control. */ +#define DOEPCTL_EPTYP_ISO (1U<<18) /**< Isochronous. */ +#define DOEPCTL_EPTYP_BULK (2U<<18) /**< Bulk. */ +#define DOEPCTL_EPTYP_INTR (3U<<18) /**< Interrupt. */ +#define DOEPCTL_NAKSTS (1U<<17) /**< NAK status. */ +#define DOEPCTL_EONUM (1U<<16) /**< Even/odd frame. */ +#define DOEPCTL_DPID (1U<<16) /**< Endpoint data PID. */ +#define DOEPCTL_USBAEP (1U<<15) /**< USB active endpoint. */ +#define DOEPCTL_MPSIZ_MASK (0x3FFU<<0) /**< Maximum Packet size mask. */ +#define DOEPCTL_MPSIZ(n) ((n)<<0) /**< Maximum Packet size value. */ +/** @} */ + +/** + * @name DOEPINT register bit definitions + * @{ + */ +#define DOEPINT_B2BSTUP (1U<<6) /**< Back-to-back SETUP packets + received. */ +#define DOEPINT_OTEPDIS (1U<<4) /**< OUT token received when + endpoint disabled. */ +#define DOEPINT_STUP (1U<<3) /**< SETUP phase done. */ +#define DOEPINT_EPDISD (1U<<1) /**< Endpoint disabled + interrupt. */ +#define DOEPINT_XFRC (1U<<0) /**< Transfer completed + interrupt. */ +/** @} */ + +/** + * @name DOEPTSIZ register bit definitions + * @{ + */ +#define DOEPTSIZ_RXDPID_MASK (3U<<29) /**< Received data PID mask. */ +#define DOEPTSIZ_RXDPID(n) ((n)<<29) /**< Received data PID value. */ +#define DOEPTSIZ_STUPCNT_MASK (3U<<29) /**< SETUP packet count mask. */ +#define DOEPTSIZ_STUPCNT(n) ((n)<<29) /**< SETUP packet count value. */ +#define DOEPTSIZ_PKTCNT_MASK (0x3FFU<<19)/**< Packet count mask. */ +#define DOEPTSIZ_PKTCNT(n) ((n)<<19) /**< Packet count value. */ +#define DOEPTSIZ_XFRSIZ_MASK (0x7FFFFU<<0)/**< Transfer size mask. */ +#define DOEPTSIZ_XFRSIZ(n) ((n)<<0) /**< Transfer size value. */ +/** @} */ + +/** + * @name PCGCCTL register bit definitions + * @{ + */ +#define PCGCCTL_PHYSUSP (1U<<4) /**< PHY Suspended. */ +#define PCGCCTL_GATEHCLK (1U<<1) /**< Gate HCLK. */ +#define PCGCCTL_STPPCLK (1U<<0) /**< Stop PCLK. */ +/** @} */ + +/** + * @brief OTG_FS registers block memory address. + */ +#define OTG_FS_ADDR 0x50000000 + +/** + * @brief OTG_HS registers block memory address. + */ +#define OTG_HS_ADDR 0x40040000 + +/** + * @brief Accesses to the OTG_FS registers block. + */ +#define OTG_FS ((stm32_otg_t *)OTG_FS_ADDR) + +/** + * @brief Accesses to the OTG_HS registers block. + */ +#define OTG_HS ((stm32_otg_t *)OTG_HS_ADDR) + +#endif /* _STM32_OTG_H_ */ + +/** @} */ diff --git a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c index 5455f52..3abab1c 100644 --- a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c @@ -1,1604 +1,1604 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-
-#if HAL_USE_USBH
-#include "usbh/internal.h"
-#include <string.h>
-
-#if USBH_LLD_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBH_LLD_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBH_LLD_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBH_LLD_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status);
-static void _try_commit_np(USBHDriver *host);
-static void otg_rxfifo_flush(USBHDriver *usbp);
-static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo);
-
-/*===========================================================================*/
-/* Little helper functions. */
-/*===========================================================================*/
-static inline void _move_to_pending_queue(usbh_ep_t *ep) {
- list_move_tail(&ep->node, ep->pending_list);
-}
-
-static inline usbh_urb_t *_active_urb(usbh_ep_t *ep) {
- return list_first_entry(&ep->urb_list, usbh_urb_t, node);
-}
-
-static inline void _save_dt_mask(usbh_ep_t *ep, uint32_t hctsiz) {
- ep->dt_mask = hctsiz & HCTSIZ_DPID_MASK;
-}
-
-#if 1
-#define _transfer_completed _transfer_completedI
-#else
-static inline void _transfer_completed(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalSysLockFromISR();
- _transfer_completedI(ep, urb, status);
- osalSysUnlockFromISR();
-}
-#endif
-
-/*===========================================================================*/
-/* Functions called from many places. */
-/*===========================================================================*/
-static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalDbgCheckClassI();
-
- urb->queued = FALSE;
-
- /* remove URB from EP's queue */
- list_del_init(&urb->node);
-
- /* Call the callback function now, so that if it calls usbhURBSubmitI,
- * the list_empty check below will be false. Also, note that the
- * if (list_empty(&ep->node)) {
- * ...
- * }
- * in usbh_lld_urb_submit will be false, since the endpoint is
- * still in the active queue.
- */
- _usbh_urb_completeI(urb, status);
-
- if (list_empty(&ep->urb_list)) {
- /* no more URBs to process in this EP, remove EP from the host's queue */
- list_del_init(&ep->node);
- } else {
- /* more URBs to process */
- _move_to_pending_queue(ep);
- }
-}
-
-static void _halt_channel(USBHDriver *host, stm32_hc_management_t *hcm, usbh_lld_halt_reason_t reason) {
- (void)host;
-
- if (hcm->halt_reason != USBH_LLD_HALTREASON_NONE) {
- uwarnf("\t%s: Repeated halt (original=%d, new=%d)", hcm->ep->name, hcm->halt_reason, reason);
- return;
- }
-
-#if CH_DBG_ENABLE_CHECKS
- if (usbhEPIsPeriodic(hcm->ep)) {
- osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK);
- } else {
- osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK);
- }
-#endif
-
- hcm->halt_reason = reason;
- hcm->hc->HCCHAR |= HCCHAR_CHENA | HCCHAR_CHDIS;
-}
-
-static void _release_channel(USBHDriver *host, stm32_hc_management_t *hcm) {
-// static const char *reason[] = {"XFRC", "XFRC", "NAK", "STALL", "ERROR", "ABORT"};
-// udbgf("\t%s: release (%s)", hcm->ep->name, reason[hcm->halt_reason]);
- hcm->hc->HCINTMSK = 0;
- host->otg->HAINTMSK &= ~hcm->haintmsk;
- hcm->halt_reason = USBH_LLD_HALTREASON_NONE;
- if (usbhEPIsPeriodic(hcm->ep)) {
- list_add(&hcm->node, &host->ch_free[0]);
- } else {
- list_add(&hcm->node, &host->ch_free[1]);
- }
- hcm->ep->xfer.hcm = 0;
- hcm->ep = 0;
-}
-
-static bool _activate_ep(USBHDriver *host, usbh_ep_t *ep) {
- struct list_head *list;
- uint16_t spc;
-
- osalDbgCheck(ep->xfer.hcm == NULL);
-
- if (usbhEPIsPeriodic(ep)) {
- list = &host->ch_free[0];
- spc = (host->otg->HPTXSTS >> 16) & 0xff;
- } else {
- list = &host->ch_free[1];
- spc = (host->otg->HNPTXSTS >> 16) & 0xff;
- }
-
- if (list_empty(list)) {
- uwarnf("\t%s: No free %s channels", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP");
- return FALSE;
- }
-
- if (spc <= STM32_USBH_MIN_QSPACE) {
- uwarnf("\t%s: No space in %s Queue (spc=%d)", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP", spc);
- return FALSE;
- }
-
- /* get the first channel */
- stm32_hc_management_t *hcm = list_first_entry(list, stm32_hc_management_t, node);
- osalDbgCheck((hcm->halt_reason == USBH_LLD_HALTREASON_NONE) && (hcm->ep == NULL));
-
- usbh_urb_t *const urb = _active_urb(ep);
- uint32_t hcintmsk = ep->hcintmsk;
- uint32_t hcchar = ep->hcchar;
- uint16_t mps = ep->wMaxPacketSize;
-
- uint32_t xfer_packets;
- uint32_t xfer_len = 0; //Initialize just to shut up a compiler warning
-
- osalDbgCheck(urb->status == USBH_URBSTATUS_PENDING);
-
- /* check if the URB is a new one, or we must continue a previously started URB */
- if (urb->queued == FALSE) {
- /* prepare EP for a new URB */
- if (ep->type == USBH_EPTYPE_CTRL) {
- xfer_len = 8;
- ep->xfer.buf = (uint8_t *)urb->setup_buff;
- ep->dt_mask = HCTSIZ_DPID_SETUP;
- ep->in = FALSE;
- ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_SETUP;
- } else {
- xfer_len = urb->requestedLength;
- ep->xfer.buf = urb->buff;
- }
- ep->xfer.error_count = 0;
- //urb->status = USBH_URBSTATUS_QUEUED;
- } else {
- osalDbgCheck(urb->requestedLength >= urb->actualLength);
-
- if (ep->type == USBH_EPTYPE_CTRL) {
- switch (ep->xfer.u.ctrl_phase) {
- case USBH_LLD_CTRLPHASE_SETUP:
- xfer_len = 8;
- ep->xfer.buf = (uint8_t *)urb->setup_buff;
- ep->dt_mask = HCTSIZ_DPID_SETUP;
- break;
- case USBH_LLD_CTRLPHASE_DATA:
- xfer_len = urb->requestedLength - urb->actualLength;
- ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength;
- break;
- case USBH_LLD_CTRLPHASE_STATUS:
- xfer_len = 0;
- ep->dt_mask = HCTSIZ_DPID_DATA1;
- ep->xfer.error_count = 0;
- break;
- default:
- osalDbgCheck(0);
- }
- if (ep->in) {
- hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM;
- hcchar |= HCCHAR_EPDIR;
- }
- } else {
- xfer_len = urb->requestedLength - urb->actualLength;
- ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength;
- }
-
- if (ep->xfer.error_count)
- hcintmsk |= HCINTMSK_ACKM;
-
- }
- ep->xfer.partial = 0;
-
- if (ep->type == USBH_EPTYPE_ISO) {
- ep->dt_mask = HCTSIZ_DPID_DATA0;
-
- /* [USB 2.0 spec, 5.6.4]: A host must not issue more than 1
- * transaction in a (micro)frame for an isochronous endpoint
- * unless the endpoint is high-speed, high-bandwidth.
- */
- if (xfer_len > mps)
- xfer_len = mps;
- } else if (xfer_len > 0x7FFFF) {
- xfer_len = 0x7FFFF - mps + 1;
- }
-
- /* calculate required packets */
- if (xfer_len) {
- xfer_packets = (xfer_len + mps - 1) / mps;
-
- if (xfer_packets > 0x3FF) {
- xfer_packets = 0x3FF;
- xfer_len = xfer_packets * mps;
- }
- } else {
- xfer_packets = 1; /* Need 1 packet for transfer length of 0 */
- }
-
- if (ep->in)
- xfer_len = xfer_packets * mps;
-
- /* Clear old interrupt conditions,
- * configure transfer size,
- * enable required interrupts */
- stm32_otg_host_chn_t *const hc = hcm->hc;
- hc->HCINT = 0xffffffff;
- hc->HCTSIZ = ep->dt_mask
- | HCTSIZ_PKTCNT(xfer_packets)
- | HCTSIZ_XFRSIZ(xfer_len);
- hc->HCINTMSK = hcintmsk;
-
- /* Queue the transfer for the next frame (no effect for non-periodic transfers) */
- if (!(host->otg->HFNUM & 1))
- hcchar |= HCCHAR_ODDFRM;
-
- /* configure channel characteristics and queue a request */
- hc->HCCHAR = hcchar;
- if (ep->in && (xfer_packets > 1)) {
- /* For IN transfers, try to queue two back-to-back packets.
- * This results in a 1% performance gain for Full Speed transfers
- */
- if (--spc > STM32_USBH_MIN_QSPACE) {
- hc->HCCHAR |= HCCHAR_CHENA;
- } else {
- uwarnf("\t%s: Could not queue back-to-back packets", ep->name);
- }
- }
-
- if (urb->queued == FALSE) {
- urb->queued = TRUE;
- udbgf("\t%s: Start (%dB)", ep->name, xfer_len);
- } else {
- udbgf("\t%s: Restart (%dB)", ep->name, xfer_len);
- }
-
- ep->xfer.len = xfer_len;
- ep->xfer.packets = (uint16_t)xfer_packets;
-
- /* remove the channel from the free list, link endpoint <-> channel and move to the active queue*/
- list_del(&hcm->node);
- ep->xfer.hcm = hcm;
- hcm->ep = ep;
- list_move_tail(&ep->node, ep->active_list);
-
-
- stm32_otg_t *const otg = host->otg;
-
- /* enable this channel's interrupt and global channel interrupt */
- otg->HAINTMSK |= hcm->haintmsk;
- if (ep->in) {
- otg->GINTMSK |= GINTMSK_HCM;
- } else if (usbhEPIsPeriodic(ep)) {
- otg->GINTMSK |= GINTMSK_HCM | GINTMSK_PTXFEM;
- } else {
- //TODO: write to the FIFO now
- otg->GINTMSK |= GINTMSK_HCM | GINTMSK_NPTXFEM;
- }
-
- return TRUE;
-}
-
-static bool _update_urb(usbh_ep_t *ep, uint32_t hctsiz, usbh_urb_t *urb, bool completed) {
- uint32_t len;
-
- if (!completed) {
- len = ep->wMaxPacketSize * (ep->xfer.packets - ((hctsiz & HCTSIZ_PKTCNT_MASK) >> 19));
- } else {
- if (ep->in) {
- len = ep->xfer.len - ((hctsiz & HCTSIZ_XFRSIZ_MASK) >> 0);
- } else {
- len = ep->xfer.len;
- }
- osalDbgCheck(len == ep->xfer.partial); //TODO: if len == ep->xfer.partial, use this instead of the above code
- }
-
-#if 1
- osalDbgAssert(urb->actualLength + len <= urb->requestedLength, "what happened?");
-#else
- if (urb->actualLength + len > urb->requestedLength) {
- uerrf("\t%s: Trimming actualLength %u -> %u", ep->name, urb->actualLength + len, urb->requestedLength);
- urb->actualLength = urb->requestedLength;
- return TRUE;
- }
-#endif
-
- urb->actualLength += len;
- if ((urb->actualLength == urb->requestedLength)
- || (ep->in && completed && (hctsiz & HCTSIZ_XFRSIZ_MASK)))
- return TRUE;
-
- return FALSE;
-}
-
-static void _try_commit_np(USBHDriver *host) {
- usbh_ep_t *item, *tmp;
-
- list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_CTRL], node) {
- if (!_activate_ep(host, item))
- return;
- }
-
- list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_BULK], node) {
- if (!_activate_ep(host, item))
- return;
- }
-}
-
-static void _try_commit_p(USBHDriver *host, bool sof) {
- usbh_ep_t *item, *tmp;
-
- list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_ISO], node) {
- if (!_activate_ep(host, item))
- return;
- }
-
- list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_INT], node) {
- osalDbgCheck(item);
- /* TODO: improve this */
- if (sof && item->xfer.u.frame_counter)
- --item->xfer.u.frame_counter;
-
- if (item->xfer.u.frame_counter == 0) {
- if (!_activate_ep(host, item))
- return;
- item->xfer.u.frame_counter = item->bInterval;
- }
- }
-
- if (list_empty(&host->ep_pending_lists[USBH_EPTYPE_ISO])
- && list_empty(&host->ep_pending_lists[USBH_EPTYPE_INT])) {
- host->otg->GINTMSK &= ~GINTMSK_SOFM;
- } else {
- host->otg->GINTMSK |= GINTMSK_SOFM;
- }
-}
-
-static void _purge_queue(USBHDriver *host, struct list_head *list) {
- usbh_ep_t *ep, *tmp;
- list_for_each_entry_safe(ep, usbh_ep_t, tmp, list, node) {
- usbh_urb_t *const urb = _active_urb(ep);
- stm32_hc_management_t *const hcm = ep->xfer.hcm;
- uwarnf("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name);
- if (hcm) {
- uwarnf("\t%s: URB had channel %d assigned, halt_reason = %d", ep->name, hcm - host->channels, hcm->halt_reason);
- _release_channel(host, hcm);
- _update_urb(ep, hcm->hc->HCTSIZ, urb, FALSE);
- }
- _transfer_completed(ep, urb, USBH_URBSTATUS_DISCONNECTED);
- }
-}
-
-static void _purge_active(USBHDriver *host) {
- _purge_queue(host, &host->ep_active_lists[0]);
- _purge_queue(host, &host->ep_active_lists[1]);
- _purge_queue(host, &host->ep_active_lists[2]);
- _purge_queue(host, &host->ep_active_lists[3]);
-}
-
-static void _purge_pending(USBHDriver *host) {
- _purge_queue(host, &host->ep_pending_lists[0]);
- _purge_queue(host, &host->ep_pending_lists[1]);
- _purge_queue(host, &host->ep_pending_lists[2]);
- _purge_queue(host, &host->ep_pending_lists[3]);
-}
-
-static uint32_t _write_packet(struct list_head *list, uint32_t space_available) {
- usbh_ep_t *ep;
-
- uint32_t remaining = 0;
-
- list_for_each_entry(ep, usbh_ep_t, list, node) {
- if (ep->in || (ep->xfer.hcm->halt_reason != USBH_LLD_HALTREASON_NONE))
- continue;
-
- int32_t rem = ep->xfer.len - ep->xfer.partial;
- osalDbgCheck(rem >= 0);
- if (rem <= 0)
- continue;
-
- remaining += rem;
-
- if (!space_available) {
- if (remaining)
- break;
-
- continue;
- }
-
- /* write one packet only */
- if (rem > ep->wMaxPacketSize)
- rem = ep->wMaxPacketSize;
-
- /* round up to dwords */
- uint32_t words = (rem + 3) / 4;
-
- if (words > space_available)
- words = space_available;
-
- space_available -= words;
-
- uint32_t written = words * 4;
- if ((int32_t)written > rem)
- written = rem;
-
- volatile uint32_t *dest = ep->xfer.hcm->fifo;
- uint32_t *src = (uint32_t *)ep->xfer.buf;
- udbgf("\t%s: write %d words (%dB), partial=%d", ep->name, words, written, ep->xfer.partial);
- while (words--) {
- *dest = *src++;
- }
-
- ep->xfer.buf += written;
- ep->xfer.partial += written;
-
- remaining -= written;
- }
-
- return remaining;
-}
-
-
-/*===========================================================================*/
-/* API. */
-/*===========================================================================*/
-
-void usbh_lld_ep_object_init(usbh_ep_t *ep) {
-/* CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
- * STALL si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP)
- * ACK si si si si si si no no ep->type != ISO
- * NAK si si si si si si no no ep->type != ISO
- * BBERR si no si no si no si no ep->in
- * TRERR si si si si si si si no ep->type != ISO || ep->in
- * DTERR si no si no si no no no ep->type != ISO && ep->in
- * FRMOR no no si si no no si si ep->type = PERIODIC
- */
- USBHDriver *host = ep->device->host;
- uint32_t hcintmsk = HCINTMSK_CHHM | HCINTMSK_XFRCM | HCINTMSK_AHBERRM;
-
- switch (ep->type) {
- case USBH_EPTYPE_ISO:
- hcintmsk |= HCINTMSK_FRMORM;
- if (ep->in) {
- hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_BBERRM;
- }
- break;
- case USBH_EPTYPE_INT:
- hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_FRMORM | HCINTMSK_STALLM | HCINTMSK_NAKM;
- if (ep->in) {
- hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM;
- }
- ep->xfer.u.frame_counter = 1;
- break;
- case USBH_EPTYPE_CTRL:
- hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM;
- break;
- case USBH_EPTYPE_BULK:
- hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM;
- if (ep->in) {
- hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM;
- }
- break;
- default:
- chDbgCheck(0);
- }
- ep->active_list = &host->ep_active_lists[ep->type];
- ep->pending_list = &host->ep_pending_lists[ep->type];
- INIT_LIST_HEAD(&ep->urb_list);
- INIT_LIST_HEAD(&ep->node);
-
- ep->hcintmsk = hcintmsk;
- ep->hcchar = HCCHAR_CHENA
- | HCCHAR_DAD(ep->device->address)
- | HCCHAR_MCNT(1)
- | HCCHAR_EPTYP(ep->type)
- | ((ep->device->speed == USBH_DEVSPEED_LOW) ? HCCHAR_LSDEV : 0)
- | (ep->in ? HCCHAR_EPDIR : 0)
- | HCCHAR_EPNUM(ep->address)
- | HCCHAR_MPS(ep->wMaxPacketSize);
-}
-
-void usbh_lld_ep_open(usbh_ep_t *ep) {
- uinfof("\t%s: Open EP", ep->name);
- ep->status = USBH_EPSTATUS_OPEN;
- osalOsRescheduleS();
-}
-
-void usbh_lld_ep_close(usbh_ep_t *ep) {
- usbh_urb_t *urb, *tmp;
- uinfof("\t%s: Closing EP...", ep->name);
- list_for_each_entry_safe(urb, usbh_urb_t, tmp, &ep->urb_list, node) {
- uinfof("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name);
- _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_DISCONNECTED);
- }
- uinfof("\t%s: Closed", ep->name);
- ep->status = USBH_EPSTATUS_CLOSED;
- osalOsRescheduleS();
-}
-
-void usbh_lld_urb_submit(usbh_urb_t *urb) {
- usbh_ep_t *const ep = urb->ep;
-
- /* add the URB to the EP's queue */
- list_add_tail(&urb->node, &ep->urb_list);
-
- /* check if the EP wasn't in any queue (pending nor active) */
- if (list_empty(&ep->node)) {
-
- /* add the EP to the pending queue */
- _move_to_pending_queue(ep);
-
- if (usbhEPIsPeriodic(ep)) {
- ep->device->host->otg->GINTMSK |= GINTMSK_SOFM;
- } else {
- /* try to queue non-periodic transfers */
- _try_commit_np(ep->device->host);
- }
- }
-}
-
-bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalDbgCheck(usbhURBIsBusy(urb));
-
- usbh_ep_t *const ep = urb->ep;
- osalDbgCheck(ep);
- stm32_hc_management_t *const hcm = ep->xfer.hcm;
-
- if ((hcm != NULL) && (urb == _active_urb(ep))) {
- /* This URB is active (channel assigned, top of the EP's URB list) */
-
- if (hcm->halt_reason == USBH_LLD_HALTREASON_NONE) {
- /* The channel is not being halted */
- urb->status = status;
- _halt_channel(ep->device->host, hcm, USBH_LLD_HALTREASON_ABORT);
- } else {
- /* The channel is being halted, so we can't re-halt it. The CHH interrupt will
- * be in charge of completing the transfer, but the URB will not have the specified status.
- */
- }
- return FALSE;
- }
-
- /* This URB is active, we can cancel it now */
- _transfer_completedI(ep, urb, status);
-
- return TRUE;
-}
-
-
-/*===========================================================================*/
-/* Channel Interrupts. */
-/*===========================================================================*/
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si si si si si si no no ep->type != ISO && !ep->in
-static inline void _ack_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- (void)host;
- osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "ACK should not happen in ISO endpoints");
- hcm->ep->xfer.error_count = 0;
- hc->HCINTMSK &= ~HCINTMSK_ACKM;
- udbgf("\t%s: ACK", hcm->ep->name);
-}
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si no si no si no no no ep->type != ISO && ep->in
-static inline void _dterr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- (void)host;
- osalDbgAssert(hcm->ep->in && (hcm->ep->type != USBH_EPTYPE_ISO), "DTERR should not happen in OUT or ISO endpoints");
-#if 0
- hc->HCINTMSK &= ~(HCINTMSK_DTERRM | HCINTMSK_ACKM);
- hcm->ep->xfer.error_count = 0;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR);
-#else
- /* restart directly, no need to halt it in this case */
- hcm->ep->xfer.error_count = 0;
- hc->HCINTMSK &= ~HCINTMSK_ACKM;
- hc->HCCHAR |= HCCHAR_CHENA;
-#endif
- uerrf("\t%s: DTERR", hcm->ep->name);
-}
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si no si no si no si no ep->in
-static inline void _bberr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- osalDbgAssert(hcm->ep->in, "BBERR should not happen in OUT endpoints");
- hc->HCINTMSK &= ~HCINTMSK_BBERRM;
- hcm->ep->xfer.error_count = 3;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR);
- uerrf("\t%s: BBERR", hcm->ep->name);
-}
-
-///CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si si si si si si si no ep->type != ISO || ep->in
-static inline void _trerr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- osalDbgAssert(hcm->ep->in || (hcm->ep->type != USBH_EPTYPE_ISO), "TRERR should not happen in ISO OUT endpoints");
- hc->HCINTMSK &= ~HCINTMSK_TRERRM;
- ++hcm->ep->xfer.error_count;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR);
- uerrf("\t%s: TRERR", hcm->ep->name);
-}
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// no no si si no no si si ep->type = PERIODIC
-static inline void _frmor_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- osalDbgAssert(usbhEPIsPeriodic(hcm->ep), "FRMOR should not happen in non-periodic endpoints");
- hc->HCINTMSK &= ~HCINTMSK_FRMORM;
- hcm->ep->xfer.error_count = 3;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR);
- uerrf("\t%s: FRMOR", hcm->ep->name);
-}
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si si si si si si no no ep->type != ISO
-static inline void _nak_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "NAK should not happen in ISO endpoints");
- if (!hcm->ep->in || (hcm->ep->type == USBH_EPTYPE_INT)) {
- hc->HCINTMSK &= ~HCINTMSK_NAKM;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_NAK);
- } else {
- /* restart directly, no need to halt it in this case */
- hcm->ep->xfer.error_count = 0;
- hc->HCINTMSK &= ~HCINTMSK_ACKM;
- hc->HCCHAR |= HCCHAR_CHENA;
- }
- udbgf("\t%s: NAK", hcm->ep->name);
-}
-
-//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT)
-// si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP)
-static inline void _stall_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "STALL should not happen in ISO endpoints");
- hc->HCINTMSK &= ~HCINTMSK_STALLM;
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_STALL);
- uwarnf("\t%s: STALL", hcm->ep->name);
-}
-
-static void _complete_bulk_int(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) {
- _release_channel(host, hcm);
- _save_dt_mask(ep, hctsiz);
- if (_update_urb(ep, hctsiz, urb, TRUE)) {
- udbgf("\t%s: done", ep->name);
- _transfer_completed(ep, urb, USBH_URBSTATUS_OK);
- } else {
- osalDbgCheck(urb->requestedLength > 0x7FFFF);
- uwarnf("\t%s: incomplete", ep->name);
- _move_to_pending_queue(ep);
- }
- if (usbhEPIsPeriodic(ep)) {
- _try_commit_p(host, FALSE);
- } else {
- _try_commit_np(host);
- }
-}
-
-static void _complete_control(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) {
- osalDbgCheck(ep->xfer.u.ctrl_phase != USBH_LLD_CTRLPHASE_SETUP);
-
- _release_channel(host, hcm);
- if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_DATA) {
- if (_update_urb(ep, hctsiz, urb, TRUE)) {
- udbgf("\t%s: DATA done", ep->name);
- ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS;
- ep->in = !ep->in;
- } else {
- osalDbgCheck(urb->requestedLength > 0x7FFFF);
- uwarnf("\t%s: DATA incomplete", ep->name);
- _save_dt_mask(ep, hctsiz);
- }
- _move_to_pending_queue(ep);
- } else {
- osalDbgCheck(ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_STATUS);
- udbgf("\t%s: STATUS done", ep->name);
- _transfer_completed(ep, urb, USBH_URBSTATUS_OK);
- }
- _try_commit_np(host);
-}
-
-static void _complete_control_setup(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb) {
- _release_channel(host, hcm);
- if (urb->requestedLength) {
- udbgf("\t%s: SETUP done -> DATA", ep->name);
- ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_DATA;
- ep->in = *((uint8_t *)urb->setup_buff) & 0x80 ? TRUE : FALSE;
- ep->dt_mask = HCTSIZ_DPID_DATA1;
- ep->xfer.error_count = 0;
- } else {
- udbgf("\t%s: SETUP done -> STATUS", ep->name);
- ep->in = TRUE;
- ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS;
- }
- _move_to_pending_queue(ep);
- _try_commit_np(host);
-}
-
-static void _complete_iso(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) {
- udbgf("\t%s: done", hcm->ep->name);
- _release_channel(host, hcm);
- _update_urb(ep, hctsiz, urb, TRUE);
- _transfer_completed(ep, urb, USBH_URBSTATUS_OK);
- _try_commit_p(host, FALSE);
-}
-
-static inline void _xfrc_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
- usbh_ep_t *const ep = hcm->ep;
- usbh_urb_t *const urb = _active_urb(ep);
- osalDbgCheck(urb);
- uint32_t hctsiz = hc->HCTSIZ;
-
- hc->HCINTMSK &= ~HCINTMSK_XFRCM;
-
- switch (ep->type) {
- case USBH_EPTYPE_CTRL:
- if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP) {
- _complete_control_setup(host, hcm, ep, urb);
- } else if (ep->in) {
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC);
- } else {
- _complete_control(host, hcm, ep, urb, hctsiz);
- }
- break;
-
- case USBH_EPTYPE_BULK:
- if (ep->in) {
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC);
- } else {
- _complete_bulk_int(host, hcm, ep, urb, hctsiz);
- }
- break;
-
- case USBH_EPTYPE_INT:
- if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) {
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC);
- } else {
- _complete_bulk_int(host, hcm, ep, urb, hctsiz);
- }
- break;
-
- case USBH_EPTYPE_ISO:
- if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) {
- _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC);
- } else {
- _complete_iso(host, hcm, ep, urb, hctsiz);
- }
- break;
- }
-}
-
-static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) {
-
- usbh_ep_t *const ep = hcm->ep;
- usbh_urb_t *const urb = _active_urb(ep);
- osalDbgCheck(urb);
- uint32_t hctsiz = hc->HCTSIZ;
- usbh_lld_halt_reason_t reason = hcm->halt_reason;
-
- //osalDbgCheck(reason != USBH_LLD_HALTREASON_NONE);
- if (reason == USBH_LLD_HALTREASON_NONE) {
- uwarnf("\tCHH: ch=%d, USBH_LLD_HALTREASON_NONE", hcm - host->channels);
- return;
- }
-
- if (reason == USBH_LLD_HALTREASON_XFRC) {
- osalDbgCheck(ep->in);
- switch (ep->type) {
- case USBH_EPTYPE_CTRL:
- _complete_control(host, hcm, ep, urb, hctsiz);
- break;
- case USBH_EPTYPE_BULK:
- case USBH_EPTYPE_INT:
- _complete_bulk_int(host, hcm, ep, urb, hctsiz);
- break;
- case USBH_EPTYPE_ISO:
- _complete_iso(host, hcm, ep, urb, hctsiz);
- break;
- }
- } else {
- _release_channel(host, hcm);
- _save_dt_mask(ep, hctsiz);
- bool done = _update_urb(ep, hctsiz, urb, FALSE);
-
- switch (reason) {
- case USBH_LLD_HALTREASON_NAK:
- if ((ep->type == USBH_EPTYPE_INT) && ep->in) {
- _transfer_completed(ep, urb, USBH_URBSTATUS_TIMEOUT);
- } else {
- ep->xfer.error_count = 0;
- _move_to_pending_queue(ep);
- }
- break;
-
- case USBH_LLD_HALTREASON_STALL:
- if ((ep->type == USBH_EPTYPE_CTRL) && (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP)) {
- uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name);
- }
- _transfer_completed(ep, urb, USBH_URBSTATUS_STALL);
- break;
-
- case USBH_LLD_HALTREASON_ERROR:
- if ((ep->type == USBH_EPTYPE_ISO) || done || (ep->xfer.error_count >= 3)) {
- _transfer_completed(ep, urb, USBH_URBSTATUS_ERROR);
- } else {
- uerrf("\t%s: err=%d, done=%d, retry", ep->name, ep->xfer.error_count, done);
- _move_to_pending_queue(ep);
- }
- break;
-
- case USBH_LLD_HALTREASON_ABORT:
- uwarnf("\t%s: Abort", ep->name);
- _transfer_completed(ep, urb, urb->status);
- break;
-
- default:
- osalDbgCheck(0);
- break;
- }
-
- if (usbhEPIsPeriodic(ep)) {
- _try_commit_p(host, FALSE);
- } else {
- _try_commit_np(host);
- }
- }
-}
-
-static void _hcint_n_int(USBHDriver *host, uint8_t chn) {
-
- stm32_hc_management_t *const hcm = &host->channels[chn];
- stm32_otg_host_chn_t *const hc = hcm->hc;
-
- uint32_t hcint = hc->HCINT;
- hcint &= hc->HCINTMSK;
- hc->HCINT = hcint;
-
- osalDbgCheck((hcint & HCINTMSK_AHBERRM) == 0);
- osalDbgCheck(hcm->ep);
-
- if (hcint & HCINTMSK_STALLM)
- _stall_int(host, hcm, hc);
- if (hcint & HCINTMSK_NAKM)
- _nak_int(host, hcm, hc);
- if (hcint & HCINTMSK_ACKM)
- _ack_int(host, hcm, hc);
- if (hcint & HCINTMSK_TRERRM)
- _trerr_int(host, hcm, hc);
- if (hcint & HCINTMSK_BBERRM)
- _bberr_int(host, hcm, hc);
- if (hcint & HCINTMSK_FRMORM)
- _frmor_int(host, hcm, hc);
- if (hcint & HCINTMSK_DTERRM)
- _dterr_int(host, hcm, hc);
- if (hcint & HCINTMSK_XFRCM)
- _xfrc_int(host, hcm, hc);
- if (hcint & HCINTMSK_CHHM)
- _chh_int(host, hcm, hc);
-}
-
-static inline void _hcint_int(USBHDriver *host) {
- uint32_t haint;
-
- haint = host->otg->HAINT;
- haint &= host->otg->HAINTMSK;
-
- if (!haint) {
- uerrf("HAINT=%08x, HAINTMSK=%08x", host->otg->HAINT, host->otg->HAINTMSK);
- return;
- }
-
-#if 1 //channel lookup loop
- uint8_t i;
- for (i = 0; haint && (i < host->channels_number); i++) {
- if (haint & (1 << i)) {
- _hcint_n_int(host, i);
- haint &= ~(1 << i);
- }
- }
-#else //faster calculation, with __CLZ (count leading zeroes)
- while (haint) {
- uint8_t chn = (uint8_t)(31 - __CLZ(haint));
- osalDbgAssert(chn < host->channels_number, "what?");
- haint &= ~host->channels[chn].haintmsk;
- _hcint_n_int(host, chn);
- }
-#endif
-}
-
-
-/*===========================================================================*/
-/* Host interrupts. */
-/*===========================================================================*/
-static inline void _sof_int(USBHDriver *host) {
- udbg("SOF");
- _try_commit_p(host, TRUE);
-}
-
-static inline void _rxflvl_int(USBHDriver *host) {
-
- stm32_otg_t *const otg = host->otg;
-
- otg->GINTMSK &= ~GINTMSK_RXFLVLM;
- while (otg->GINTSTS & GINTSTS_RXFLVL) {
- uint32_t grxstsp = otg->GRXSTSP;
- osalDbgCheck((grxstsp & GRXSTSP_CHNUM_MASK) < host->channels_number);
- stm32_hc_management_t *const hcm = &host->channels[grxstsp & GRXSTSP_CHNUM_MASK];
- uint32_t hctsiz = hcm->hc->HCTSIZ;
-
- if ((grxstsp & GRXSTSP_PKTSTS_MASK) == GRXSTSP_PKTSTS(2)) {
- /* 0010: IN data packet received */
- usbh_ep_t *const ep = hcm->ep;
- osalDbgCheck(ep);
-
- /* restart the channel ASAP */
- if (hctsiz & HCTSIZ_PKTCNT_MASK) {
-#if CH_DBG_ENABLE_CHECKS
- if (usbhEPIsPeriodic(ep)) {
- osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK);
- } else {
- osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK);
- }
-#endif
- hcm->hc->HCCHAR |= HCCHAR_CHENA;
- }
-
- udbgf("\t%s: RXFLVL rx=%dB, rem=%dB (%dpkts)",
- ep->name,
- (grxstsp & GRXSTSP_BCNT_MASK) >> 4,
- (hctsiz & HCTSIZ_XFRSIZ_MASK),
- (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19);
-
- /* Read */
- uint32_t *dest = (uint32_t *)ep->xfer.buf;
- volatile uint32_t *const src = hcm->fifo;
-
- uint32_t bcnt = (grxstsp & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF;
- osalDbgCheck(bcnt + ep->xfer.partial <= ep->xfer.len);
-
- //TODO: optimize this
- uint32_t words = bcnt / 4;
- uint8_t bytes = bcnt & 3;
- while (words--) {
- *dest++ = *src;
- }
- if (bytes) {
- uint32_t r = *src;
- uint8_t *bsrc = (uint8_t *)&r;
- uint8_t *bdest = (uint8_t *)dest;
- do {
- *bdest++ = *bsrc++;
- } while (--bytes);
- }
-
- ep->xfer.buf += bcnt;
- ep->xfer.partial += bcnt;
-
-#if 0 //STM32_USBH_CHANNELS_NP > 1
- /* check bug */
- if (hctsiz & HCTSIZ_PKTCNT_MASK) {
- uint32_t pkt = (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19;
- uint32_t siz = (hctsiz & HCTSIZ_XFRSIZ_MASK);
- if (pkt * ep->wMaxPacketSize != siz) {
- uerrf("\t%s: whatttt???", ep->name);
- }
- }
-#endif
-
-#if USBH_DEBUG_ENABLE && USBH_LLD_DEBUG_ENABLE_ERRORS
- } else {
- /* 0011: IN transfer completed (triggers an interrupt)
- * 0101: Data toggle error (triggers an interrupt)
- * 0111: Channel halted (triggers an interrupt)
- */
- switch (grxstsp & GRXSTSP_PKTSTS_MASK) {
- case GRXSTSP_PKTSTS(3):
- case GRXSTSP_PKTSTS(5):
- case GRXSTSP_PKTSTS(7):
- break;
- default:
- uerrf("\tRXFLVL: ch=%d, UNK=%d", grxstsp & GRXSTSP_CHNUM_MASK, (grxstsp & GRXSTSP_PKTSTS_MASK) >> 17);
- break;
- }
-#endif
- }
- }
- otg->GINTMSK |= GINTMSK_RXFLVLM;
-}
-
-static inline void _nptxfe_int(USBHDriver *host) {
- uint32_t rem;
- stm32_otg_t *const otg = host->otg;
-
- rem = _write_packet(&host->ep_active_lists[USBH_EPTYPE_CTRL],
- otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK);
-
- rem += _write_packet(&host->ep_active_lists[USBH_EPTYPE_BULK],
- otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK);
-
-// if (rem)
-// otg->GINTMSK |= GINTMSK_NPTXFEM;
-
- if (!rem)
- otg->GINTMSK &= ~GINTMSK_NPTXFEM;
-
-}
-
-static inline void _ptxfe_int(USBHDriver *host) {
- //TODO: implement
- (void)host;
- uinfo("PTXFE");
-}
-
-static inline void _discint_int(USBHDriver *host) {
- uint32_t hprt = host->otg->HPRT;
-
- uwarn("\tDISCINT");
-
- if (!(hprt & HPRT_PCSTS)) {
- host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE);
- host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE;
- }
- _purge_active(host);
- _purge_pending(host);
-}
-
-static inline void _hprtint_int(USBHDriver *host) {
- stm32_otg_t *const otg = host->otg;
- uint32_t hprt = otg->HPRT;
-
- /* note: writing PENA = 1 actually disables the port */
- uint32_t hprt_clr = hprt & ~(HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG);
-
- if (hprt & HPRT_PCDET) {
- hprt_clr |= HPRT_PCDET;
- if (hprt & HPRT_PCSTS) {
- uinfo("\tHPRT: Port connection detected");
- host->rootport.lld_status |= USBH_PORTSTATUS_CONNECTION;
- host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION;
- } else {
- uinfo("\tHPRT: Port disconnection detected");
- }
- }
-
- if (hprt & HPRT_PENCHNG) {
- hprt_clr |= HPRT_PENCHNG;
- if (hprt & HPRT_PENA) {
- uinfo("\tHPRT: Port enabled");
- host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE;
- host->rootport.lld_status &= ~(USBH_PORTSTATUS_HIGH_SPEED | USBH_PORTSTATUS_LOW_SPEED);
-
- /* Make sure the FIFOs are flushed. */
- otg_txfifo_flush(host, 0x10);
- otg_rxfifo_flush(host);
-
- /* Clear all pending HC Interrupts */
- uint8_t i;
- for (i = 0; i < host->channels_number; i++) {
- otg->hc[i].HCINTMSK = 0;
- otg->hc[i].HCINT = 0xFFFFFFFF;
- }
-
- /* configure speed */
- if ((hprt & HPRT_PSPD_MASK) == HPRT_PSPD_LS) {
- host->rootport.lld_status |= USBH_PORTSTATUS_LOW_SPEED;
- otg->HFIR = 6000;
- otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_6;
- } else {
- otg->HFIR = 48000;
- otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_48;
- }
- } else {
- if (hprt & HPRT_PCSTS) {
- if (hprt & HPRT_POCA) {
- uerr("\tHPRT: Port disabled due to overcurrent");
- } else {
- uerr("\tHPRT: Port disabled due to port babble");
- }
- } else {
- uerr("\tHPRT: Port disabled due to disconnect");
- }
-
- _purge_active(host);
- _purge_pending(host);
-
- host->rootport.lld_status &= ~USBH_PORTSTATUS_ENABLE;
- }
- host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE;
- }
-
- if (hprt & HPRT_POCCHNG) {
- hprt_clr |= HPRT_POCCHNG;
- if (hprt & HPRT_POCA) {
- uerr("\tHPRT: Overcurrent");
- host->rootport.lld_status |= USBH_PORTSTATUS_OVERCURRENT;
- } else {
- udbg("\tHPRT: Clear overcurrent");
- host->rootport.lld_status &= ~USBH_PORTSTATUS_OVERCURRENT;
- }
- host->rootport.lld_c_status |= USBH_PORTSTATUS_C_OVERCURRENT;
- }
-
- otg->HPRT = hprt_clr;
-}
-
-static void usb_lld_serve_interrupt(USBHDriver *host) {
- osalDbgCheck(host && (host->status != USBH_STATUS_STOPPED));
-
- stm32_otg_t *const otg = host->otg;
- uint32_t gintsts = otg->GINTSTS;
-
- /* check host mode */
- if (!(gintsts & GINTSTS_CMOD)) {
- uerr("Device mode");
- otg->GINTSTS = gintsts;
- return;
- }
-
- /* check mismatch */
- if (gintsts & GINTSTS_MMIS) {
- uerr("Mode Mismatch");
- otg->GINTSTS = gintsts;
- return;
- }
-
- gintsts &= otg->GINTMSK;
- if (!gintsts) {
- uwarnf("GINTSTS=%08x, GINTMSK=%08x", otg->GINTSTS, otg->GINTMSK);
- return;
- }
-// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM);
- otg->GINTSTS = gintsts;
-
- if (gintsts & GINTSTS_SOF)
- _sof_int(host);
- if (gintsts & GINTSTS_RXFLVL)
- _rxflvl_int(host);
- if (gintsts & GINTSTS_HPRTINT)
- _hprtint_int(host);
- if (gintsts & GINTSTS_DISCINT)
- _discint_int(host);
- if (gintsts & GINTSTS_HCINT)
- _hcint_int(host);
- if (gintsts & GINTSTS_NPTXFE)
- _nptxfe_int(host);
- if (gintsts & GINTSTS_PTXFE)
- _ptxfe_int(host);
- if (gintsts & GINTSTS_IPXFR) {
- uerr("IPXFRM");
- }
-}
-
-
-/*===========================================================================*/
-/* Interrupt handlers. */
-/*===========================================================================*/
-
-#if STM32_USBH_USE_OTG1
-OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) {
- OSAL_IRQ_PROLOGUE();
- osalSysLockFromISR();
- usb_lld_serve_interrupt(&USBHD1);
- osalSysUnlockFromISR();
- OSAL_IRQ_EPILOGUE();
-}
-#endif
-
-#if STM32_USBH_USE_OTG2
-OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) {
- OSAL_IRQ_PROLOGUE();
- osalSysLockFromISR();
- usb_lld_serve_interrupt(&USBHD2);
- osalSysUnlockFromISR();
- OSAL_IRQ_EPILOGUE();
-}
-#endif
-
-
-/*===========================================================================*/
-/* Initialization functions. */
-/*===========================================================================*/
-static void otg_core_reset(USBHDriver *usbp) {
- stm32_otg_t *const otgp = usbp->otg;
-
- /* Wait AHB idle condition.*/
- while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0)
- ;
-
- osalSysPolledDelayX(64);
-
- /* Core reset and delay of at least 3 PHY cycles.*/
- otgp->GRSTCTL = GRSTCTL_CSRST;
- while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0)
- ;
-
- osalSysPolledDelayX(24);
-
- /* Wait AHB idle condition.*/
- while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0)
- ;
-}
-
-static void otg_rxfifo_flush(USBHDriver *usbp) {
- stm32_otg_t *const otgp = usbp->otg;
-
- otgp->GRSTCTL = GRSTCTL_RXFFLSH;
- while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0)
- ;
- /* Wait for 3 PHY Clocks.*/
- osalSysPolledDelayX(24);
-}
-
-static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo) {
- stm32_otg_t *const otgp = usbp->otg;
-
- otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH;
- while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0)
- ;
- /* Wait for 3 PHY Clocks.*/
- osalSysPolledDelayX(24);
-}
-
-static void _init(USBHDriver *host) {
- int i;
-
- usbhObjectInit(host);
-
-#if STM32_USBH_USE_OTG1
-#if STM32_USBH_USE_OTG2
- if (&USBHD1 == host) {
-#endif
- host->otg = OTG_FS;
- host->channels_number = STM32_OTG1_CHANNELS_NUMBER;
-#if STM32_USBH_USE_OTG2
- }
-#endif
-#endif
-
-#if STM32_USBH_USE_OTG2
-#if STM32_USBH_USE_OTG1
- if (&USBHD2 == host) {
-#endif
- host->otg = OTG_HS;
- host->channels_number = STM32_OTG2_CHANNELS_NUMBER;
-#if STM32_USBH_USE_OTG1
- }
-#endif
-#endif
- INIT_LIST_HEAD(&host->ch_free[0]);
- INIT_LIST_HEAD(&host->ch_free[1]);
- for (i = 0; i < host->channels_number; i++) {
- host->channels[i].haintmsk = 1 << i;
- host->channels[i].hc = &host->otg->hc[i];
- host->channels[i].fifo = host->otg->FIFO[i];
- if (i < STM32_USBH_CHANNELS_NP) {
- list_add_tail(&host->channels[i].node, &host->ch_free[1]);
- } else {
- list_add_tail(&host->channels[i].node, &host->ch_free[0]);
- }
- }
- for (i = 0; i < 4; i++) {
- INIT_LIST_HEAD(&host->ep_active_lists[i]);
- INIT_LIST_HEAD(&host->ep_pending_lists[i]);
- }
-}
-
-void usbh_lld_init(void) {
-#if STM32_USBH_USE_OTG1
- _init(&USBHD1);
-#endif
-#if STM32_USBH_USE_OTG2
- _init(&USBHD2);
-#endif
-}
-
-static void _usbh_start(USBHDriver *usbh) {
- stm32_otg_t *const otgp = usbh->otg;
-
- /* Clock activation.*/
-#if STM32_USBH_USE_OTG1
-#if STM32_USBH_USE_OTG2
- if (&USBHD1 == usbh) {
-#endif
- /* OTG FS clock enable and reset.*/
- rccEnableOTG_FS(FALSE);
- rccResetOTG_FS();
-
- otgp->GINTMSK = 0;
-
- /* Enables IRQ vector.*/
- nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY);
-#if STM32_USBH_USE_OTG2
- }
-#endif
-#endif
-
-#if STM32_USBH_USE_OTG2
-#if STM32_USBH_USE_OTG1
- if (&USBHD2 == usbh) {
-#endif
- /* OTG HS clock enable and reset.*/
- rccEnableOTG_HS(FALSE);
- rccResetOTG_HS();
-
- otgp->GINTMSK = 0;
-
- /* Enables IRQ vector.*/
- nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY);
-#if STM32_USBH_USE_OTG1
- }
-#endif
-#endif
-
- otgp->GUSBCFG = GUSBCFG_PHYSEL | GUSBCFG_TRDT(5);
-
- otg_core_reset(usbh);
-
- otgp->GCCFG = GCCFG_PWRDWN;
-
- /* Forced host mode. */
- otgp->GUSBCFG = GUSBCFG_FHMOD | GUSBCFG_PHYSEL | GUSBCFG_TRDT(5);
-
- /* PHY enabled.*/
- otgp->PCGCCTL = 0;
-
- /* Internal FS PHY activation.*/
-#if defined(BOARD_OTG_NOVBUSSENS)
- otgp->GCCFG = GCCFG_NOVBUSSENS | GCCFG_PWRDWN;
-#else
- otgp->GCCFG = GCCFG_PWRDWN;
-#endif
-
- /* 48MHz 1.1 PHY.*/
- otgp->HCFG = HCFG_FSLSS | HCFG_FSLSPCS_48;
-
- /* Interrupts on FIFOs half empty.*/
- otgp->GAHBCFG = 0;
-
- otgp->GOTGINT = 0xFFFFFFFF;
-
- otgp->HPRT |= HPRT_PPWR;
-
- /* without this delay, the FIFO sizes are set INcorrectly */
- osalThreadSleepS(MS2ST(200));
-
-#define HNPTXFSIZ DIEPTXF0
-#if STM32_USBH_USE_OTG1
-#if STM32_USBH_USE_OTG2
- if (&USBHD1 == usbh) {
-#endif
- otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4);
- otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4);
- otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4);
-#if STM32_USBH_USE_OTG2
- }
-#endif
-#endif
-#if STM32_USBH_USE_OTG2
-#if STM32_USBH_USE_OTG1
- if (&USBHD2 == usbh) {
-#endif
- otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4);
- otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4);
- otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4);
-#if STM32_USBH_USE_OTG1
- }
-#endif
-#endif
-
- otg_txfifo_flush(usbh, 0x10);
- otg_rxfifo_flush(usbh);
-
- otgp->GINTSTS = 0xffffffff;
- otgp->GINTMSK = GINTMSK_DISCM /*| GINTMSK_PTXFEM*/ | GINTMSK_HCM | GINTMSK_HPRTM
- /*| GINTMSK_IPXFRM | GINTMSK_NPTXFEM*/ | GINTMSK_RXFLVLM
- /*| GINTMSK_SOFM */ | GINTMSK_MMISM;
-
- usbh->rootport.lld_status = USBH_PORTSTATUS_POWER;
- usbh->rootport.lld_c_status = 0;
-
- /* Global interrupts enable.*/
- otgp->GAHBCFG |= GAHBCFG_GINTMSK;
-}
-
-void usbh_lld_start(USBHDriver *usbh) {
- if (usbh->status != USBH_STATUS_STOPPED) return;
- _usbh_start(usbh);
-}
-
-/*===========================================================================*/
-/* Root Hub request handler. */
-/*===========================================================================*/
-usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest,
- uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf) {
-
- uint16_t typereq = (bmRequestType << 8) | bRequest;
-
- switch (typereq) {
- case ClearHubFeature:
- switch (wvalue) {
- case USBH_HUB_FEAT_C_HUB_LOCAL_POWER:
- case USBH_HUB_FEAT_C_HUB_OVER_CURRENT:
- break;
- default:
- osalDbgAssert(0, "invalid wvalue");
- }
- break;
-
- case ClearPortFeature:
- chDbgAssert(windex == 1, "invalid windex");
-
- osalSysLock();
- switch (wvalue) {
- case USBH_PORT_FEAT_ENABLE:
- case USBH_PORT_FEAT_SUSPEND:
- case USBH_PORT_FEAT_POWER:
- chDbgAssert(0, "unimplemented"); /* TODO */
- break;
-
- case USBH_PORT_FEAT_INDICATOR:
- chDbgAssert(0, "unsupported");
- break;
-
- case USBH_PORT_FEAT_C_CONNECTION:
- usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_CONNECTION;
- break;
-
- case USBH_PORT_FEAT_C_RESET:
- usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_RESET;
- break;
-
- case USBH_PORT_FEAT_C_ENABLE:
- usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_ENABLE;
- break;
-
- case USBH_PORT_FEAT_C_SUSPEND:
- usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_SUSPEND;
- break;
-
- case USBH_PORT_FEAT_C_OVERCURRENT:
- usbh->rootport.lld_c_status &= USBH_PORTSTATUS_C_OVERCURRENT;
- break;
-
- default:
- osalDbgAssert(0, "invalid wvalue");
- break;
- }
- osalOsRescheduleS();
- osalSysUnlock();
- break;
-
- case GetHubDescriptor:
- /*dev_dbg(hsotg->dev, "GetHubDescriptor\n");
- hub_desc = (struct usb_hub_descriptor *)buf;
- hub_desc->bDescLength = 9;
- hub_desc->bDescriptorType = USB_DT_HUB;
- hub_desc->bNbrPorts = 1;
- hub_desc->wHubCharacteristics =
- cpu_to_le16(HUB_CHAR_COMMON_LPSM |
- HUB_CHAR_INDV_PORT_OCPM);
- hub_desc->bPwrOn2PwrGood = 1;
- hub_desc->bHubContrCurrent = 0;
- hub_desc->u.hs.DeviceRemovable[0] = 0;
- hub_desc->u.hs.DeviceRemovable[1] = 0xff;*/
- break;
-
- case GetHubStatus:
- osalDbgCheck(wlength >= 4);
- *(uint32_t *)buf = 0;
- break;
-
- case GetPortStatus:
- chDbgAssert(windex == 1, "invalid windex");
- osalDbgCheck(wlength >= 4);
- osalSysLock();
- *(uint32_t *)buf = usbh->rootport.lld_status | (usbh->rootport.lld_c_status << 16);
- osalOsRescheduleS();
- osalSysUnlock();
- break;
-
- case SetHubFeature:
- chDbgAssert(0, "unsupported");
- break;
-
- case SetPortFeature:
- chDbgAssert(windex == 1, "invalid windex");
-
- switch (wvalue) {
- case USBH_PORT_FEAT_TEST:
- case USBH_PORT_FEAT_SUSPEND:
- case USBH_PORT_FEAT_POWER:
- chDbgAssert(0, "unimplemented"); /* TODO */
- break;
-
- case USBH_PORT_FEAT_RESET: {
- osalSysLock();
- stm32_otg_t *const otg = usbh->otg;
- uint32_t hprt;
- otg->PCGCCTL = 0;
- hprt = otg->HPRT;
- /* note: writing PENA = 1 actually disables the port */
- hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG );
- otg->HPRT = hprt | HPRT_PRST;
- osalThreadSleepS(MS2ST(60));
- otg->HPRT = hprt;
- usbh->rootport.lld_c_status |= USBH_PORTSTATUS_C_RESET;
- osalOsRescheduleS();
- osalSysUnlock();
- } break;
-
- case USBH_PORT_FEAT_INDICATOR:
- chDbgAssert(0, "unsupported");
- break;
-
- default:
- osalDbgAssert(0, "invalid wvalue");
- break;
- }
- break;
-
- default:
- osalDbgAssert(0, "invalid typereq");
- break;
- }
-
- return USBH_URBSTATUS_OK;
-}
-
-uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh) {
- osalSysLock();
- if (usbh->rootport.lld_c_status) {
- osalOsRescheduleS();
- osalSysUnlock();
- return 1 << 1;
- }
- osalOsRescheduleS();
- osalSysUnlock();
- return 0;
-}
-
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +#if HAL_USE_USBH +#include "usbh/internal.h" +#include <string.h> + +#if USBH_LLD_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBH_LLD_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + +static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status); +static void _try_commit_np(USBHDriver *host); +static void otg_rxfifo_flush(USBHDriver *usbp); +static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo); + +/*===========================================================================*/ +/* Little helper functions. */ +/*===========================================================================*/ +static inline void _move_to_pending_queue(usbh_ep_t *ep) { + list_move_tail(&ep->node, ep->pending_list); +} + +static inline usbh_urb_t *_active_urb(usbh_ep_t *ep) { + return list_first_entry(&ep->urb_list, usbh_urb_t, node); +} + +static inline void _save_dt_mask(usbh_ep_t *ep, uint32_t hctsiz) { + ep->dt_mask = hctsiz & HCTSIZ_DPID_MASK; +} + +#if 1 +#define _transfer_completed _transfer_completedI +#else +static inline void _transfer_completed(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { + osalSysLockFromISR(); + _transfer_completedI(ep, urb, status); + osalSysUnlockFromISR(); +} +#endif + +/*===========================================================================*/ +/* Functions called from many places. */ +/*===========================================================================*/ +static void _transfer_completedI(usbh_ep_t *ep, usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheckClassI(); + + urb->queued = FALSE; + + /* remove URB from EP's queue */ + list_del_init(&urb->node); + + /* Call the callback function now, so that if it calls usbhURBSubmitI, + * the list_empty check below will be false. Also, note that the + * if (list_empty(&ep->node)) { + * ... + * } + * in usbh_lld_urb_submit will be false, since the endpoint is + * still in the active queue. + */ + _usbh_urb_completeI(urb, status); + + if (list_empty(&ep->urb_list)) { + /* no more URBs to process in this EP, remove EP from the host's queue */ + list_del_init(&ep->node); + } else { + /* more URBs to process */ + _move_to_pending_queue(ep); + } +} + +static void _halt_channel(USBHDriver *host, stm32_hc_management_t *hcm, usbh_lld_halt_reason_t reason) { + (void)host; + + if (hcm->halt_reason != USBH_LLD_HALTREASON_NONE) { + uwarnf("\t%s: Repeated halt (original=%d, new=%d)", hcm->ep->name, hcm->halt_reason, reason); + return; + } + +#if CH_DBG_ENABLE_CHECKS + if (usbhEPIsPeriodic(hcm->ep)) { + osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); + } else { + osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); + } +#endif + + hcm->halt_reason = reason; + hcm->hc->HCCHAR |= HCCHAR_CHENA | HCCHAR_CHDIS; +} + +static void _release_channel(USBHDriver *host, stm32_hc_management_t *hcm) { +// static const char *reason[] = {"XFRC", "XFRC", "NAK", "STALL", "ERROR", "ABORT"}; +// udbgf("\t%s: release (%s)", hcm->ep->name, reason[hcm->halt_reason]); + hcm->hc->HCINTMSK = 0; + host->otg->HAINTMSK &= ~hcm->haintmsk; + hcm->halt_reason = USBH_LLD_HALTREASON_NONE; + if (usbhEPIsPeriodic(hcm->ep)) { + list_add(&hcm->node, &host->ch_free[0]); + } else { + list_add(&hcm->node, &host->ch_free[1]); + } + hcm->ep->xfer.hcm = 0; + hcm->ep = 0; +} + +static bool _activate_ep(USBHDriver *host, usbh_ep_t *ep) { + struct list_head *list; + uint16_t spc; + + osalDbgCheck(ep->xfer.hcm == NULL); + + if (usbhEPIsPeriodic(ep)) { + list = &host->ch_free[0]; + spc = (host->otg->HPTXSTS >> 16) & 0xff; + } else { + list = &host->ch_free[1]; + spc = (host->otg->HNPTXSTS >> 16) & 0xff; + } + + if (list_empty(list)) { + uwarnf("\t%s: No free %s channels", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP"); + return FALSE; + } + + if (spc <= STM32_USBH_MIN_QSPACE) { + uwarnf("\t%s: No space in %s Queue (spc=%d)", ep->name, usbhEPIsPeriodic(ep) ? "P" : "NP", spc); + return FALSE; + } + + /* get the first channel */ + stm32_hc_management_t *hcm = list_first_entry(list, stm32_hc_management_t, node); + osalDbgCheck((hcm->halt_reason == USBH_LLD_HALTREASON_NONE) && (hcm->ep == NULL)); + + usbh_urb_t *const urb = _active_urb(ep); + uint32_t hcintmsk = ep->hcintmsk; + uint32_t hcchar = ep->hcchar; + uint16_t mps = ep->wMaxPacketSize; + + uint32_t xfer_packets; + uint32_t xfer_len = 0; //Initialize just to shut up a compiler warning + + osalDbgCheck(urb->status == USBH_URBSTATUS_PENDING); + + /* check if the URB is a new one, or we must continue a previously started URB */ + if (urb->queued == FALSE) { + /* prepare EP for a new URB */ + if (ep->type == USBH_EPTYPE_CTRL) { + xfer_len = 8; + ep->xfer.buf = (uint8_t *)urb->setup_buff; + ep->dt_mask = HCTSIZ_DPID_SETUP; + ep->in = FALSE; + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_SETUP; + } else { + xfer_len = urb->requestedLength; + ep->xfer.buf = urb->buff; + } + ep->xfer.error_count = 0; + //urb->status = USBH_URBSTATUS_QUEUED; + } else { + osalDbgCheck(urb->requestedLength >= urb->actualLength); + + if (ep->type == USBH_EPTYPE_CTRL) { + switch (ep->xfer.u.ctrl_phase) { + case USBH_LLD_CTRLPHASE_SETUP: + xfer_len = 8; + ep->xfer.buf = (uint8_t *)urb->setup_buff; + ep->dt_mask = HCTSIZ_DPID_SETUP; + break; + case USBH_LLD_CTRLPHASE_DATA: + xfer_len = urb->requestedLength - urb->actualLength; + ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; + break; + case USBH_LLD_CTRLPHASE_STATUS: + xfer_len = 0; + ep->dt_mask = HCTSIZ_DPID_DATA1; + ep->xfer.error_count = 0; + break; + default: + osalDbgCheck(0); + } + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + hcchar |= HCCHAR_EPDIR; + } + } else { + xfer_len = urb->requestedLength - urb->actualLength; + ep->xfer.buf = (uint8_t *) urb->buff + urb->actualLength; + } + + if (ep->xfer.error_count) + hcintmsk |= HCINTMSK_ACKM; + + } + ep->xfer.partial = 0; + + if (ep->type == USBH_EPTYPE_ISO) { + ep->dt_mask = HCTSIZ_DPID_DATA0; + + /* [USB 2.0 spec, 5.6.4]: A host must not issue more than 1 + * transaction in a (micro)frame for an isochronous endpoint + * unless the endpoint is high-speed, high-bandwidth. + */ + if (xfer_len > mps) + xfer_len = mps; + } else if (xfer_len > 0x7FFFF) { + xfer_len = 0x7FFFF - mps + 1; + } + + /* calculate required packets */ + if (xfer_len) { + xfer_packets = (xfer_len + mps - 1) / mps; + + if (xfer_packets > 0x3FF) { + xfer_packets = 0x3FF; + xfer_len = xfer_packets * mps; + } + } else { + xfer_packets = 1; /* Need 1 packet for transfer length of 0 */ + } + + if (ep->in) + xfer_len = xfer_packets * mps; + + /* Clear old interrupt conditions, + * configure transfer size, + * enable required interrupts */ + stm32_otg_host_chn_t *const hc = hcm->hc; + hc->HCINT = 0xffffffff; + hc->HCTSIZ = ep->dt_mask + | HCTSIZ_PKTCNT(xfer_packets) + | HCTSIZ_XFRSIZ(xfer_len); + hc->HCINTMSK = hcintmsk; + + /* Queue the transfer for the next frame (no effect for non-periodic transfers) */ + if (!(host->otg->HFNUM & 1)) + hcchar |= HCCHAR_ODDFRM; + + /* configure channel characteristics and queue a request */ + hc->HCCHAR = hcchar; + if (ep->in && (xfer_packets > 1)) { + /* For IN transfers, try to queue two back-to-back packets. + * This results in a 1% performance gain for Full Speed transfers + */ + if (--spc > STM32_USBH_MIN_QSPACE) { + hc->HCCHAR |= HCCHAR_CHENA; + } else { + uwarnf("\t%s: Could not queue back-to-back packets", ep->name); + } + } + + if (urb->queued == FALSE) { + urb->queued = TRUE; + udbgf("\t%s: Start (%dB)", ep->name, xfer_len); + } else { + udbgf("\t%s: Restart (%dB)", ep->name, xfer_len); + } + + ep->xfer.len = xfer_len; + ep->xfer.packets = (uint16_t)xfer_packets; + + /* remove the channel from the free list, link endpoint <-> channel and move to the active queue*/ + list_del(&hcm->node); + ep->xfer.hcm = hcm; + hcm->ep = ep; + list_move_tail(&ep->node, ep->active_list); + + + stm32_otg_t *const otg = host->otg; + + /* enable this channel's interrupt and global channel interrupt */ + otg->HAINTMSK |= hcm->haintmsk; + if (ep->in) { + otg->GINTMSK |= GINTMSK_HCM; + } else if (usbhEPIsPeriodic(ep)) { + otg->GINTMSK |= GINTMSK_HCM | GINTMSK_PTXFEM; + } else { + //TODO: write to the FIFO now + otg->GINTMSK |= GINTMSK_HCM | GINTMSK_NPTXFEM; + } + + return TRUE; +} + +static bool _update_urb(usbh_ep_t *ep, uint32_t hctsiz, usbh_urb_t *urb, bool completed) { + uint32_t len; + + if (!completed) { + len = ep->wMaxPacketSize * (ep->xfer.packets - ((hctsiz & HCTSIZ_PKTCNT_MASK) >> 19)); + } else { + if (ep->in) { + len = ep->xfer.len - ((hctsiz & HCTSIZ_XFRSIZ_MASK) >> 0); + } else { + len = ep->xfer.len; + } + osalDbgCheck(len == ep->xfer.partial); //TODO: if len == ep->xfer.partial, use this instead of the above code + } + +#if 1 + osalDbgAssert(urb->actualLength + len <= urb->requestedLength, "what happened?"); +#else + if (urb->actualLength + len > urb->requestedLength) { + uerrf("\t%s: Trimming actualLength %u -> %u", ep->name, urb->actualLength + len, urb->requestedLength); + urb->actualLength = urb->requestedLength; + return TRUE; + } +#endif + + urb->actualLength += len; + if ((urb->actualLength == urb->requestedLength) + || (ep->in && completed && (hctsiz & HCTSIZ_XFRSIZ_MASK))) + return TRUE; + + return FALSE; +} + +static void _try_commit_np(USBHDriver *host) { + usbh_ep_t *item, *tmp; + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_CTRL], node) { + if (!_activate_ep(host, item)) + return; + } + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_BULK], node) { + if (!_activate_ep(host, item)) + return; + } +} + +static void _try_commit_p(USBHDriver *host, bool sof) { + usbh_ep_t *item, *tmp; + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_ISO], node) { + if (!_activate_ep(host, item)) + return; + } + + list_for_each_entry_safe(item, usbh_ep_t, tmp, &host->ep_pending_lists[USBH_EPTYPE_INT], node) { + osalDbgCheck(item); + /* TODO: improve this */ + if (sof && item->xfer.u.frame_counter) + --item->xfer.u.frame_counter; + + if (item->xfer.u.frame_counter == 0) { + if (!_activate_ep(host, item)) + return; + item->xfer.u.frame_counter = item->bInterval; + } + } + + if (list_empty(&host->ep_pending_lists[USBH_EPTYPE_ISO]) + && list_empty(&host->ep_pending_lists[USBH_EPTYPE_INT])) { + host->otg->GINTMSK &= ~GINTMSK_SOFM; + } else { + host->otg->GINTMSK |= GINTMSK_SOFM; + } +} + +static void _purge_queue(USBHDriver *host, struct list_head *list) { + usbh_ep_t *ep, *tmp; + list_for_each_entry_safe(ep, usbh_ep_t, tmp, list, node) { + usbh_urb_t *const urb = _active_urb(ep); + stm32_hc_management_t *const hcm = ep->xfer.hcm; + uwarnf("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); + if (hcm) { + uwarnf("\t%s: URB had channel %d assigned, halt_reason = %d", ep->name, hcm - host->channels, hcm->halt_reason); + _release_channel(host, hcm); + _update_urb(ep, hcm->hc->HCTSIZ, urb, FALSE); + } + _transfer_completed(ep, urb, USBH_URBSTATUS_DISCONNECTED); + } +} + +static void _purge_active(USBHDriver *host) { + _purge_queue(host, &host->ep_active_lists[0]); + _purge_queue(host, &host->ep_active_lists[1]); + _purge_queue(host, &host->ep_active_lists[2]); + _purge_queue(host, &host->ep_active_lists[3]); +} + +static void _purge_pending(USBHDriver *host) { + _purge_queue(host, &host->ep_pending_lists[0]); + _purge_queue(host, &host->ep_pending_lists[1]); + _purge_queue(host, &host->ep_pending_lists[2]); + _purge_queue(host, &host->ep_pending_lists[3]); +} + +static uint32_t _write_packet(struct list_head *list, uint32_t space_available) { + usbh_ep_t *ep; + + uint32_t remaining = 0; + + list_for_each_entry(ep, usbh_ep_t, list, node) { + if (ep->in || (ep->xfer.hcm->halt_reason != USBH_LLD_HALTREASON_NONE)) + continue; + + int32_t rem = ep->xfer.len - ep->xfer.partial; + osalDbgCheck(rem >= 0); + if (rem <= 0) + continue; + + remaining += rem; + + if (!space_available) { + if (remaining) + break; + + continue; + } + + /* write one packet only */ + if (rem > ep->wMaxPacketSize) + rem = ep->wMaxPacketSize; + + /* round up to dwords */ + uint32_t words = (rem + 3) / 4; + + if (words > space_available) + words = space_available; + + space_available -= words; + + uint32_t written = words * 4; + if ((int32_t)written > rem) + written = rem; + + volatile uint32_t *dest = ep->xfer.hcm->fifo; + uint32_t *src = (uint32_t *)ep->xfer.buf; + udbgf("\t%s: write %d words (%dB), partial=%d", ep->name, words, written, ep->xfer.partial); + while (words--) { + *dest = *src++; + } + + ep->xfer.buf += written; + ep->xfer.partial += written; + + remaining -= written; + } + + return remaining; +} + + +/*===========================================================================*/ +/* API. */ +/*===========================================================================*/ + +void usbh_lld_ep_object_init(usbh_ep_t *ep) { +/* CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) + * STALL si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) + * ACK si si si si si si no no ep->type != ISO + * NAK si si si si si si no no ep->type != ISO + * BBERR si no si no si no si no ep->in + * TRERR si si si si si si si no ep->type != ISO || ep->in + * DTERR si no si no si no no no ep->type != ISO && ep->in + * FRMOR no no si si no no si si ep->type = PERIODIC + */ + USBHDriver *host = ep->device->host; + uint32_t hcintmsk = HCINTMSK_CHHM | HCINTMSK_XFRCM | HCINTMSK_AHBERRM; + + switch (ep->type) { + case USBH_EPTYPE_ISO: + hcintmsk |= HCINTMSK_FRMORM; + if (ep->in) { + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_BBERRM; + } + break; + case USBH_EPTYPE_INT: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_FRMORM | HCINTMSK_STALLM | HCINTMSK_NAKM; + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + } + ep->xfer.u.frame_counter = 1; + break; + case USBH_EPTYPE_CTRL: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; + break; + case USBH_EPTYPE_BULK: + hcintmsk |= HCINTMSK_TRERRM | HCINTMSK_STALLM | HCINTMSK_NAKM; + if (ep->in) { + hcintmsk |= HCINTMSK_DTERRM | HCINTMSK_BBERRM; + } + break; + default: + chDbgCheck(0); + } + ep->active_list = &host->ep_active_lists[ep->type]; + ep->pending_list = &host->ep_pending_lists[ep->type]; + INIT_LIST_HEAD(&ep->urb_list); + INIT_LIST_HEAD(&ep->node); + + ep->hcintmsk = hcintmsk; + ep->hcchar = HCCHAR_CHENA + | HCCHAR_DAD(ep->device->address) + | HCCHAR_MCNT(1) + | HCCHAR_EPTYP(ep->type) + | ((ep->device->speed == USBH_DEVSPEED_LOW) ? HCCHAR_LSDEV : 0) + | (ep->in ? HCCHAR_EPDIR : 0) + | HCCHAR_EPNUM(ep->address) + | HCCHAR_MPS(ep->wMaxPacketSize); +} + +void usbh_lld_ep_open(usbh_ep_t *ep) { + uinfof("\t%s: Open EP", ep->name); + ep->status = USBH_EPSTATUS_OPEN; + osalOsRescheduleS(); +} + +void usbh_lld_ep_close(usbh_ep_t *ep) { + usbh_urb_t *urb, *tmp; + uinfof("\t%s: Closing EP...", ep->name); + list_for_each_entry_safe(urb, usbh_urb_t, tmp, &ep->urb_list, node) { + uinfof("\t%s: Abort URB, USBH_URBSTATUS_DISCONNECTED", ep->name); + _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_DISCONNECTED); + } + uinfof("\t%s: Closed", ep->name); + ep->status = USBH_EPSTATUS_CLOSED; + osalOsRescheduleS(); +} + +void usbh_lld_urb_submit(usbh_urb_t *urb) { + usbh_ep_t *const ep = urb->ep; + + /* add the URB to the EP's queue */ + list_add_tail(&urb->node, &ep->urb_list); + + /* check if the EP wasn't in any queue (pending nor active) */ + if (list_empty(&ep->node)) { + + /* add the EP to the pending queue */ + _move_to_pending_queue(ep); + + if (usbhEPIsPeriodic(ep)) { + ep->device->host->otg->GINTMSK |= GINTMSK_SOFM; + } else { + /* try to queue non-periodic transfers */ + _try_commit_np(ep->device->host); + } + } +} + +bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheck(usbhURBIsBusy(urb)); + + usbh_ep_t *const ep = urb->ep; + osalDbgCheck(ep); + stm32_hc_management_t *const hcm = ep->xfer.hcm; + + if ((hcm != NULL) && (urb == _active_urb(ep))) { + /* This URB is active (channel assigned, top of the EP's URB list) */ + + if (hcm->halt_reason == USBH_LLD_HALTREASON_NONE) { + /* The channel is not being halted */ + urb->status = status; + _halt_channel(ep->device->host, hcm, USBH_LLD_HALTREASON_ABORT); + } else { + /* The channel is being halted, so we can't re-halt it. The CHH interrupt will + * be in charge of completing the transfer, but the URB will not have the specified status. + */ + } + return FALSE; + } + + /* This URB is active, we can cancel it now */ + _transfer_completedI(ep, urb, status); + + return TRUE; +} + + +/*===========================================================================*/ +/* Channel Interrupts. */ +/*===========================================================================*/ + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si no no ep->type != ISO && !ep->in +static inline void _ack_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + (void)host; + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "ACK should not happen in ISO endpoints"); + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + udbgf("\t%s: ACK", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si no si no si no no no ep->type != ISO && ep->in +static inline void _dterr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + (void)host; + osalDbgAssert(hcm->ep->in && (hcm->ep->type != USBH_EPTYPE_ISO), "DTERR should not happen in OUT or ISO endpoints"); +#if 0 + hc->HCINTMSK &= ~(HCINTMSK_DTERRM | HCINTMSK_ACKM); + hcm->ep->xfer.error_count = 0; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); +#else + /* restart directly, no need to halt it in this case */ + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + hc->HCCHAR |= HCCHAR_CHENA; +#endif + uerrf("\t%s: DTERR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si no si no si no si no ep->in +static inline void _bberr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->in, "BBERR should not happen in OUT endpoints"); + hc->HCINTMSK &= ~HCINTMSK_BBERRM; + hcm->ep->xfer.error_count = 3; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: BBERR", hcm->ep->name); +} + +///CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si si no ep->type != ISO || ep->in +static inline void _trerr_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->in || (hcm->ep->type != USBH_EPTYPE_ISO), "TRERR should not happen in ISO OUT endpoints"); + hc->HCINTMSK &= ~HCINTMSK_TRERRM; + ++hcm->ep->xfer.error_count; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: TRERR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// no no si si no no si si ep->type = PERIODIC +static inline void _frmor_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(usbhEPIsPeriodic(hcm->ep), "FRMOR should not happen in non-periodic endpoints"); + hc->HCINTMSK &= ~HCINTMSK_FRMORM; + hcm->ep->xfer.error_count = 3; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_ERROR); + uerrf("\t%s: FRMOR", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si si si si si si no no ep->type != ISO +static inline void _nak_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "NAK should not happen in ISO endpoints"); + if (!hcm->ep->in || (hcm->ep->type == USBH_EPTYPE_INT)) { + hc->HCINTMSK &= ~HCINTMSK_NAKM; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_NAK); + } else { + /* restart directly, no need to halt it in this case */ + hcm->ep->xfer.error_count = 0; + hc->HCINTMSK &= ~HCINTMSK_ACKM; + hc->HCCHAR |= HCCHAR_CHENA; + } + udbgf("\t%s: NAK", hcm->ep->name); +} + +//CTRL(IN) CTRL(OUT) INT(IN) INT(OUT) BULK(IN) BULK(OUT) ISO(IN) ISO(OUT) +// si sólo DAT/STAT si si si si no no ep->type != ISO && (ep->type != CTRL || ctrlphase != SETUP) +static inline void _stall_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + osalDbgAssert(hcm->ep->type != USBH_EPTYPE_ISO, "STALL should not happen in ISO endpoints"); + hc->HCINTMSK &= ~HCINTMSK_STALLM; + _halt_channel(host, hcm, USBH_LLD_HALTREASON_STALL); + uwarnf("\t%s: STALL", hcm->ep->name); +} + +static void _complete_bulk_int(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + _release_channel(host, hcm); + _save_dt_mask(ep, hctsiz); + if (_update_urb(ep, hctsiz, urb, TRUE)) { + udbgf("\t%s: done", ep->name); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + } else { + osalDbgCheck(urb->requestedLength > 0x7FFFF); + uwarnf("\t%s: incomplete", ep->name); + _move_to_pending_queue(ep); + } + if (usbhEPIsPeriodic(ep)) { + _try_commit_p(host, FALSE); + } else { + _try_commit_np(host); + } +} + +static void _complete_control(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + osalDbgCheck(ep->xfer.u.ctrl_phase != USBH_LLD_CTRLPHASE_SETUP); + + _release_channel(host, hcm); + if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_DATA) { + if (_update_urb(ep, hctsiz, urb, TRUE)) { + udbgf("\t%s: DATA done", ep->name); + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; + ep->in = !ep->in; + } else { + osalDbgCheck(urb->requestedLength > 0x7FFFF); + uwarnf("\t%s: DATA incomplete", ep->name); + _save_dt_mask(ep, hctsiz); + } + _move_to_pending_queue(ep); + } else { + osalDbgCheck(ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_STATUS); + udbgf("\t%s: STATUS done", ep->name); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + } + _try_commit_np(host); +} + +static void _complete_control_setup(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb) { + _release_channel(host, hcm); + if (urb->requestedLength) { + udbgf("\t%s: SETUP done -> DATA", ep->name); + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_DATA; + ep->in = *((uint8_t *)urb->setup_buff) & 0x80 ? TRUE : FALSE; + ep->dt_mask = HCTSIZ_DPID_DATA1; + ep->xfer.error_count = 0; + } else { + udbgf("\t%s: SETUP done -> STATUS", ep->name); + ep->in = TRUE; + ep->xfer.u.ctrl_phase = USBH_LLD_CTRLPHASE_STATUS; + } + _move_to_pending_queue(ep); + _try_commit_np(host); +} + +static void _complete_iso(USBHDriver *host, stm32_hc_management_t *hcm, usbh_ep_t *ep, usbh_urb_t *urb, uint32_t hctsiz) { + udbgf("\t%s: done", hcm->ep->name); + _release_channel(host, hcm); + _update_urb(ep, hctsiz, urb, TRUE); + _transfer_completed(ep, urb, USBH_URBSTATUS_OK); + _try_commit_p(host, FALSE); +} + +static inline void _xfrc_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + usbh_ep_t *const ep = hcm->ep; + usbh_urb_t *const urb = _active_urb(ep); + osalDbgCheck(urb); + uint32_t hctsiz = hc->HCTSIZ; + + hc->HCINTMSK &= ~HCINTMSK_XFRCM; + + switch (ep->type) { + case USBH_EPTYPE_CTRL: + if (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP) { + _complete_control_setup(host, hcm, ep, urb); + } else if (ep->in) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_control(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_BULK: + if (ep->in) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_INT: + if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + } + break; + + case USBH_EPTYPE_ISO: + if (ep->in && (hctsiz & HCTSIZ_PKTCNT_MASK)) { + _halt_channel(host, hcm, USBH_LLD_HALTREASON_XFRC); + } else { + _complete_iso(host, hcm, ep, urb, hctsiz); + } + break; + } +} + +static inline void _chh_int(USBHDriver *host, stm32_hc_management_t *hcm, stm32_otg_host_chn_t *hc) { + + usbh_ep_t *const ep = hcm->ep; + usbh_urb_t *const urb = _active_urb(ep); + osalDbgCheck(urb); + uint32_t hctsiz = hc->HCTSIZ; + usbh_lld_halt_reason_t reason = hcm->halt_reason; + + //osalDbgCheck(reason != USBH_LLD_HALTREASON_NONE); + if (reason == USBH_LLD_HALTREASON_NONE) { + uwarnf("\tCHH: ch=%d, USBH_LLD_HALTREASON_NONE", hcm - host->channels); + return; + } + + if (reason == USBH_LLD_HALTREASON_XFRC) { + osalDbgCheck(ep->in); + switch (ep->type) { + case USBH_EPTYPE_CTRL: + _complete_control(host, hcm, ep, urb, hctsiz); + break; + case USBH_EPTYPE_BULK: + case USBH_EPTYPE_INT: + _complete_bulk_int(host, hcm, ep, urb, hctsiz); + break; + case USBH_EPTYPE_ISO: + _complete_iso(host, hcm, ep, urb, hctsiz); + break; + } + } else { + _release_channel(host, hcm); + _save_dt_mask(ep, hctsiz); + bool done = _update_urb(ep, hctsiz, urb, FALSE); + + switch (reason) { + case USBH_LLD_HALTREASON_NAK: + if ((ep->type == USBH_EPTYPE_INT) && ep->in) { + _transfer_completed(ep, urb, USBH_URBSTATUS_TIMEOUT); + } else { + ep->xfer.error_count = 0; + _move_to_pending_queue(ep); + } + break; + + case USBH_LLD_HALTREASON_STALL: + if ((ep->type == USBH_EPTYPE_CTRL) && (ep->xfer.u.ctrl_phase == USBH_LLD_CTRLPHASE_SETUP)) { + uerrf("\t%s: Faulty device: STALLed SETUP phase", ep->name); + } + _transfer_completed(ep, urb, USBH_URBSTATUS_STALL); + break; + + case USBH_LLD_HALTREASON_ERROR: + if ((ep->type == USBH_EPTYPE_ISO) || done || (ep->xfer.error_count >= 3)) { + _transfer_completed(ep, urb, USBH_URBSTATUS_ERROR); + } else { + uerrf("\t%s: err=%d, done=%d, retry", ep->name, ep->xfer.error_count, done); + _move_to_pending_queue(ep); + } + break; + + case USBH_LLD_HALTREASON_ABORT: + uwarnf("\t%s: Abort", ep->name); + _transfer_completed(ep, urb, urb->status); + break; + + default: + osalDbgCheck(0); + break; + } + + if (usbhEPIsPeriodic(ep)) { + _try_commit_p(host, FALSE); + } else { + _try_commit_np(host); + } + } +} + +static void _hcint_n_int(USBHDriver *host, uint8_t chn) { + + stm32_hc_management_t *const hcm = &host->channels[chn]; + stm32_otg_host_chn_t *const hc = hcm->hc; + + uint32_t hcint = hc->HCINT; + hcint &= hc->HCINTMSK; + hc->HCINT = hcint; + + osalDbgCheck((hcint & HCINTMSK_AHBERRM) == 0); + osalDbgCheck(hcm->ep); + + if (hcint & HCINTMSK_STALLM) + _stall_int(host, hcm, hc); + if (hcint & HCINTMSK_NAKM) + _nak_int(host, hcm, hc); + if (hcint & HCINTMSK_ACKM) + _ack_int(host, hcm, hc); + if (hcint & HCINTMSK_TRERRM) + _trerr_int(host, hcm, hc); + if (hcint & HCINTMSK_BBERRM) + _bberr_int(host, hcm, hc); + if (hcint & HCINTMSK_FRMORM) + _frmor_int(host, hcm, hc); + if (hcint & HCINTMSK_DTERRM) + _dterr_int(host, hcm, hc); + if (hcint & HCINTMSK_XFRCM) + _xfrc_int(host, hcm, hc); + if (hcint & HCINTMSK_CHHM) + _chh_int(host, hcm, hc); +} + +static inline void _hcint_int(USBHDriver *host) { + uint32_t haint; + + haint = host->otg->HAINT; + haint &= host->otg->HAINTMSK; + + if (!haint) { + uerrf("HAINT=%08x, HAINTMSK=%08x", host->otg->HAINT, host->otg->HAINTMSK); + return; + } + +#if 1 //channel lookup loop + uint8_t i; + for (i = 0; haint && (i < host->channels_number); i++) { + if (haint & (1 << i)) { + _hcint_n_int(host, i); + haint &= ~(1 << i); + } + } +#else //faster calculation, with __CLZ (count leading zeroes) + while (haint) { + uint8_t chn = (uint8_t)(31 - __CLZ(haint)); + osalDbgAssert(chn < host->channels_number, "what?"); + haint &= ~host->channels[chn].haintmsk; + _hcint_n_int(host, chn); + } +#endif +} + + +/*===========================================================================*/ +/* Host interrupts. */ +/*===========================================================================*/ +static inline void _sof_int(USBHDriver *host) { + udbg("SOF"); + _try_commit_p(host, TRUE); +} + +static inline void _rxflvl_int(USBHDriver *host) { + + stm32_otg_t *const otg = host->otg; + + otg->GINTMSK &= ~GINTMSK_RXFLVLM; + while (otg->GINTSTS & GINTSTS_RXFLVL) { + uint32_t grxstsp = otg->GRXSTSP; + osalDbgCheck((grxstsp & GRXSTSP_CHNUM_MASK) < host->channels_number); + stm32_hc_management_t *const hcm = &host->channels[grxstsp & GRXSTSP_CHNUM_MASK]; + uint32_t hctsiz = hcm->hc->HCTSIZ; + + if ((grxstsp & GRXSTSP_PKTSTS_MASK) == GRXSTSP_PKTSTS(2)) { + /* 0010: IN data packet received */ + usbh_ep_t *const ep = hcm->ep; + osalDbgCheck(ep); + + /* restart the channel ASAP */ + if (hctsiz & HCTSIZ_PKTCNT_MASK) { +#if CH_DBG_ENABLE_CHECKS + if (usbhEPIsPeriodic(ep)) { + osalDbgCheck(host->otg->HPTXSTS & HPTXSTS_PTXQSAV_MASK); + } else { + osalDbgCheck(host->otg->HNPTXSTS & HPTXSTS_PTXQSAV_MASK); + } +#endif + hcm->hc->HCCHAR |= HCCHAR_CHENA; + } + + udbgf("\t%s: RXFLVL rx=%dB, rem=%dB (%dpkts)", + ep->name, + (grxstsp & GRXSTSP_BCNT_MASK) >> 4, + (hctsiz & HCTSIZ_XFRSIZ_MASK), + (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19); + + /* Read */ + uint32_t *dest = (uint32_t *)ep->xfer.buf; + volatile uint32_t *const src = hcm->fifo; + + uint32_t bcnt = (grxstsp & GRXSTSP_BCNT_MASK) >> GRXSTSP_BCNT_OFF; + osalDbgCheck(bcnt + ep->xfer.partial <= ep->xfer.len); + + //TODO: optimize this + uint32_t words = bcnt / 4; + uint8_t bytes = bcnt & 3; + while (words--) { + *dest++ = *src; + } + if (bytes) { + uint32_t r = *src; + uint8_t *bsrc = (uint8_t *)&r; + uint8_t *bdest = (uint8_t *)dest; + do { + *bdest++ = *bsrc++; + } while (--bytes); + } + + ep->xfer.buf += bcnt; + ep->xfer.partial += bcnt; + +#if 0 //STM32_USBH_CHANNELS_NP > 1 + /* check bug */ + if (hctsiz & HCTSIZ_PKTCNT_MASK) { + uint32_t pkt = (hctsiz & HCTSIZ_PKTCNT_MASK) >> 19; + uint32_t siz = (hctsiz & HCTSIZ_XFRSIZ_MASK); + if (pkt * ep->wMaxPacketSize != siz) { + uerrf("\t%s: whatttt???", ep->name); + } + } +#endif + +#if USBH_DEBUG_ENABLE && USBH_LLD_DEBUG_ENABLE_ERRORS + } else { + /* 0011: IN transfer completed (triggers an interrupt) + * 0101: Data toggle error (triggers an interrupt) + * 0111: Channel halted (triggers an interrupt) + */ + switch (grxstsp & GRXSTSP_PKTSTS_MASK) { + case GRXSTSP_PKTSTS(3): + case GRXSTSP_PKTSTS(5): + case GRXSTSP_PKTSTS(7): + break; + default: + uerrf("\tRXFLVL: ch=%d, UNK=%d", grxstsp & GRXSTSP_CHNUM_MASK, (grxstsp & GRXSTSP_PKTSTS_MASK) >> 17); + break; + } +#endif + } + } + otg->GINTMSK |= GINTMSK_RXFLVLM; +} + +static inline void _nptxfe_int(USBHDriver *host) { + uint32_t rem; + stm32_otg_t *const otg = host->otg; + + rem = _write_packet(&host->ep_active_lists[USBH_EPTYPE_CTRL], + otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); + + rem += _write_packet(&host->ep_active_lists[USBH_EPTYPE_BULK], + otg->HNPTXSTS & HPTXSTS_PTXFSAVL_MASK); + +// if (rem) +// otg->GINTMSK |= GINTMSK_NPTXFEM; + + if (!rem) + otg->GINTMSK &= ~GINTMSK_NPTXFEM; + +} + +static inline void _ptxfe_int(USBHDriver *host) { + //TODO: implement + (void)host; + uinfo("PTXFE"); +} + +static inline void _discint_int(USBHDriver *host) { + uint32_t hprt = host->otg->HPRT; + + uwarn("\tDISCINT"); + + if (!(hprt & HPRT_PCSTS)) { + host->rootport.lld_status &= ~(USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE); + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION | USBH_PORTSTATUS_C_ENABLE; + } + _purge_active(host); + _purge_pending(host); +} + +static inline void _hprtint_int(USBHDriver *host) { + stm32_otg_t *const otg = host->otg; + uint32_t hprt = otg->HPRT; + + /* note: writing PENA = 1 actually disables the port */ + uint32_t hprt_clr = hprt & ~(HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG); + + if (hprt & HPRT_PCDET) { + hprt_clr |= HPRT_PCDET; + if (hprt & HPRT_PCSTS) { + uinfo("\tHPRT: Port connection detected"); + host->rootport.lld_status |= USBH_PORTSTATUS_CONNECTION; + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_CONNECTION; + } else { + uinfo("\tHPRT: Port disconnection detected"); + } + } + + if (hprt & HPRT_PENCHNG) { + hprt_clr |= HPRT_PENCHNG; + if (hprt & HPRT_PENA) { + uinfo("\tHPRT: Port enabled"); + host->rootport.lld_status |= USBH_PORTSTATUS_ENABLE; + host->rootport.lld_status &= ~(USBH_PORTSTATUS_HIGH_SPEED | USBH_PORTSTATUS_LOW_SPEED); + + /* Make sure the FIFOs are flushed. */ + otg_txfifo_flush(host, 0x10); + otg_rxfifo_flush(host); + + /* Clear all pending HC Interrupts */ + uint8_t i; + for (i = 0; i < host->channels_number; i++) { + otg->hc[i].HCINTMSK = 0; + otg->hc[i].HCINT = 0xFFFFFFFF; + } + + /* configure speed */ + if ((hprt & HPRT_PSPD_MASK) == HPRT_PSPD_LS) { + host->rootport.lld_status |= USBH_PORTSTATUS_LOW_SPEED; + otg->HFIR = 6000; + otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_6; + } else { + otg->HFIR = 48000; + otg->HCFG = (otg->HCFG & ~HCFG_FSLSPCS_MASK) | HCFG_FSLSPCS_48; + } + } else { + if (hprt & HPRT_PCSTS) { + if (hprt & HPRT_POCA) { + uerr("\tHPRT: Port disabled due to overcurrent"); + } else { + uerr("\tHPRT: Port disabled due to port babble"); + } + } else { + uerr("\tHPRT: Port disabled due to disconnect"); + } + + _purge_active(host); + _purge_pending(host); + + host->rootport.lld_status &= ~USBH_PORTSTATUS_ENABLE; + } + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_ENABLE; + } + + if (hprt & HPRT_POCCHNG) { + hprt_clr |= HPRT_POCCHNG; + if (hprt & HPRT_POCA) { + uerr("\tHPRT: Overcurrent"); + host->rootport.lld_status |= USBH_PORTSTATUS_OVERCURRENT; + } else { + udbg("\tHPRT: Clear overcurrent"); + host->rootport.lld_status &= ~USBH_PORTSTATUS_OVERCURRENT; + } + host->rootport.lld_c_status |= USBH_PORTSTATUS_C_OVERCURRENT; + } + + otg->HPRT = hprt_clr; +} + +static void usb_lld_serve_interrupt(USBHDriver *host) { + osalDbgCheck(host && (host->status != USBH_STATUS_STOPPED)); + + stm32_otg_t *const otg = host->otg; + uint32_t gintsts = otg->GINTSTS; + + /* check host mode */ + if (!(gintsts & GINTSTS_CMOD)) { + uerr("Device mode"); + otg->GINTSTS = gintsts; + return; + } + + /* check mismatch */ + if (gintsts & GINTSTS_MMIS) { + uerr("Mode Mismatch"); + otg->GINTSTS = gintsts; + return; + } + + gintsts &= otg->GINTMSK; + if (!gintsts) { + uwarnf("GINTSTS=%08x, GINTMSK=%08x", otg->GINTSTS, otg->GINTMSK); + return; + } +// otg->GINTMSK &= ~(GINTMSK_NPTXFEM | GINTMSK_PTXFEM); + otg->GINTSTS = gintsts; + + if (gintsts & GINTSTS_SOF) + _sof_int(host); + if (gintsts & GINTSTS_RXFLVL) + _rxflvl_int(host); + if (gintsts & GINTSTS_HPRTINT) + _hprtint_int(host); + if (gintsts & GINTSTS_DISCINT) + _discint_int(host); + if (gintsts & GINTSTS_HCINT) + _hcint_int(host); + if (gintsts & GINTSTS_NPTXFE) + _nptxfe_int(host); + if (gintsts & GINTSTS_PTXFE) + _ptxfe_int(host); + if (gintsts & GINTSTS_IPXFR) { + uerr("IPXFRM"); + } +} + + +/*===========================================================================*/ +/* Interrupt handlers. */ +/*===========================================================================*/ + +#if STM32_USBH_USE_OTG1 +OSAL_IRQ_HANDLER(STM32_OTG1_HANDLER) { + OSAL_IRQ_PROLOGUE(); + osalSysLockFromISR(); + usb_lld_serve_interrupt(&USBHD1); + osalSysUnlockFromISR(); + OSAL_IRQ_EPILOGUE(); +} +#endif + +#if STM32_USBH_USE_OTG2 +OSAL_IRQ_HANDLER(STM32_OTG2_HANDLER) { + OSAL_IRQ_PROLOGUE(); + osalSysLockFromISR(); + usb_lld_serve_interrupt(&USBHD2); + osalSysUnlockFromISR(); + OSAL_IRQ_EPILOGUE(); +} +#endif + + +/*===========================================================================*/ +/* Initialization functions. */ +/*===========================================================================*/ +static void otg_core_reset(USBHDriver *usbp) { + stm32_otg_t *const otgp = usbp->otg; + + /* Wait AHB idle condition.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; + + osalSysPolledDelayX(64); + + /* Core reset and delay of at least 3 PHY cycles.*/ + otgp->GRSTCTL = GRSTCTL_CSRST; + while ((otgp->GRSTCTL & GRSTCTL_CSRST) != 0) + ; + + osalSysPolledDelayX(24); + + /* Wait AHB idle condition.*/ + while ((otgp->GRSTCTL & GRSTCTL_AHBIDL) == 0) + ; +} + +static void otg_rxfifo_flush(USBHDriver *usbp) { + stm32_otg_t *const otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_RXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_RXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(24); +} + +static void otg_txfifo_flush(USBHDriver *usbp, uint32_t fifo) { + stm32_otg_t *const otgp = usbp->otg; + + otgp->GRSTCTL = GRSTCTL_TXFNUM(fifo) | GRSTCTL_TXFFLSH; + while ((otgp->GRSTCTL & GRSTCTL_TXFFLSH) != 0) + ; + /* Wait for 3 PHY Clocks.*/ + osalSysPolledDelayX(24); +} + +static void _init(USBHDriver *host) { + int i; + + usbhObjectInit(host); + +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == host) { +#endif + host->otg = OTG_FS; + host->channels_number = STM32_OTG1_CHANNELS_NUMBER; +#if STM32_USBH_USE_OTG2 + } +#endif +#endif + +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == host) { +#endif + host->otg = OTG_HS; + host->channels_number = STM32_OTG2_CHANNELS_NUMBER; +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + INIT_LIST_HEAD(&host->ch_free[0]); + INIT_LIST_HEAD(&host->ch_free[1]); + for (i = 0; i < host->channels_number; i++) { + host->channels[i].haintmsk = 1 << i; + host->channels[i].hc = &host->otg->hc[i]; + host->channels[i].fifo = host->otg->FIFO[i]; + if (i < STM32_USBH_CHANNELS_NP) { + list_add_tail(&host->channels[i].node, &host->ch_free[1]); + } else { + list_add_tail(&host->channels[i].node, &host->ch_free[0]); + } + } + for (i = 0; i < 4; i++) { + INIT_LIST_HEAD(&host->ep_active_lists[i]); + INIT_LIST_HEAD(&host->ep_pending_lists[i]); + } +} + +void usbh_lld_init(void) { +#if STM32_USBH_USE_OTG1 + _init(&USBHD1); +#endif +#if STM32_USBH_USE_OTG2 + _init(&USBHD2); +#endif +} + +static void _usbh_start(USBHDriver *usbh) { + stm32_otg_t *const otgp = usbh->otg; + + /* Clock activation.*/ +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == usbh) { +#endif + /* OTG FS clock enable and reset.*/ + rccEnableOTG_FS(FALSE); + rccResetOTG_FS(); + + otgp->GINTMSK = 0; + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG1_NUMBER, STM32_USB_OTG1_IRQ_PRIORITY); +#if STM32_USBH_USE_OTG2 + } +#endif +#endif + +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == usbh) { +#endif + /* OTG HS clock enable and reset.*/ + rccEnableOTG_HS(FALSE); + rccResetOTG_HS(); + + otgp->GINTMSK = 0; + + /* Enables IRQ vector.*/ + nvicEnableVector(STM32_OTG2_NUMBER, STM32_USB_OTG2_IRQ_PRIORITY); +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + + otgp->GUSBCFG = GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); + + otg_core_reset(usbh); + + otgp->GCCFG = GCCFG_PWRDWN; + + /* Forced host mode. */ + otgp->GUSBCFG = GUSBCFG_FHMOD | GUSBCFG_PHYSEL | GUSBCFG_TRDT(5); + + /* PHY enabled.*/ + otgp->PCGCCTL = 0; + + /* Internal FS PHY activation.*/ +#if defined(BOARD_OTG_NOVBUSSENS) + otgp->GCCFG = GCCFG_NOVBUSSENS | GCCFG_PWRDWN; +#else + otgp->GCCFG = GCCFG_PWRDWN; +#endif + + /* 48MHz 1.1 PHY.*/ + otgp->HCFG = HCFG_FSLSS | HCFG_FSLSPCS_48; + + /* Interrupts on FIFOs half empty.*/ + otgp->GAHBCFG = 0; + + otgp->GOTGINT = 0xFFFFFFFF; + + otgp->HPRT |= HPRT_PPWR; + + /* without this delay, the FIFO sizes are set INcorrectly */ + osalThreadSleepS(MS2ST(200)); + +#define HNPTXFSIZ DIEPTXF0 +#if STM32_USBH_USE_OTG1 +#if STM32_USBH_USE_OTG2 + if (&USBHD1 == usbh) { +#endif + otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG1_RXFIFO_SIZE / 4); + otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_NPTXFIFO_SIZE / 4); + otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG1_RXFIFO_SIZE / 4) + (STM32_OTG1_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG1_PTXFIFO_SIZE / 4); +#if STM32_USBH_USE_OTG2 + } +#endif +#endif +#if STM32_USBH_USE_OTG2 +#if STM32_USBH_USE_OTG1 + if (&USBHD2 == usbh) { +#endif + otgp->GRXFSIZ = GRXFSIZ_RXFD(STM32_OTG2_RXFIFO_SIZE / 4); + otgp->HNPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_NPTXFIFO_SIZE / 4); + otgp->HPTXFSIZ = HPTXFSIZ_PTXSA((STM32_OTG2_RXFIFO_SIZE / 4) + (STM32_OTG2_NPTXFIFO_SIZE / 4)) | HPTXFSIZ_PTXFD(STM32_OTG2_PTXFIFO_SIZE / 4); +#if STM32_USBH_USE_OTG1 + } +#endif +#endif + + otg_txfifo_flush(usbh, 0x10); + otg_rxfifo_flush(usbh); + + otgp->GINTSTS = 0xffffffff; + otgp->GINTMSK = GINTMSK_DISCM /*| GINTMSK_PTXFEM*/ | GINTMSK_HCM | GINTMSK_HPRTM + /*| GINTMSK_IPXFRM | GINTMSK_NPTXFEM*/ | GINTMSK_RXFLVLM + /*| GINTMSK_SOFM */ | GINTMSK_MMISM; + + usbh->rootport.lld_status = USBH_PORTSTATUS_POWER; + usbh->rootport.lld_c_status = 0; + + /* Global interrupts enable.*/ + otgp->GAHBCFG |= GAHBCFG_GINTMSK; +} + +void usbh_lld_start(USBHDriver *usbh) { + if (usbh->status != USBH_STATUS_STOPPED) return; + _usbh_start(usbh); +} + +/*===========================================================================*/ +/* Root Hub request handler. */ +/*===========================================================================*/ +usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, + uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf) { + + uint16_t typereq = (bmRequestType << 8) | bRequest; + + switch (typereq) { + case ClearHubFeature: + switch (wvalue) { + case USBH_HUB_FEAT_C_HUB_LOCAL_POWER: + case USBH_HUB_FEAT_C_HUB_OVER_CURRENT: + break; + default: + osalDbgAssert(0, "invalid wvalue"); + } + break; + + case ClearPortFeature: + chDbgAssert(windex == 1, "invalid windex"); + + osalSysLock(); + switch (wvalue) { + case USBH_PORT_FEAT_ENABLE: + case USBH_PORT_FEAT_SUSPEND: + case USBH_PORT_FEAT_POWER: + chDbgAssert(0, "unimplemented"); /* TODO */ + break; + + case USBH_PORT_FEAT_INDICATOR: + chDbgAssert(0, "unsupported"); + break; + + case USBH_PORT_FEAT_C_CONNECTION: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_CONNECTION; + break; + + case USBH_PORT_FEAT_C_RESET: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_RESET; + break; + + case USBH_PORT_FEAT_C_ENABLE: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_ENABLE; + break; + + case USBH_PORT_FEAT_C_SUSPEND: + usbh->rootport.lld_c_status &= ~USBH_PORTSTATUS_C_SUSPEND; + break; + + case USBH_PORT_FEAT_C_OVERCURRENT: + usbh->rootport.lld_c_status &= USBH_PORTSTATUS_C_OVERCURRENT; + break; + + default: + osalDbgAssert(0, "invalid wvalue"); + break; + } + osalOsRescheduleS(); + osalSysUnlock(); + break; + + case GetHubDescriptor: + /*dev_dbg(hsotg->dev, "GetHubDescriptor\n"); + hub_desc = (struct usb_hub_descriptor *)buf; + hub_desc->bDescLength = 9; + hub_desc->bDescriptorType = USB_DT_HUB; + hub_desc->bNbrPorts = 1; + hub_desc->wHubCharacteristics = + cpu_to_le16(HUB_CHAR_COMMON_LPSM | + HUB_CHAR_INDV_PORT_OCPM); + hub_desc->bPwrOn2PwrGood = 1; + hub_desc->bHubContrCurrent = 0; + hub_desc->u.hs.DeviceRemovable[0] = 0; + hub_desc->u.hs.DeviceRemovable[1] = 0xff;*/ + break; + + case GetHubStatus: + osalDbgCheck(wlength >= 4); + *(uint32_t *)buf = 0; + break; + + case GetPortStatus: + chDbgAssert(windex == 1, "invalid windex"); + osalDbgCheck(wlength >= 4); + osalSysLock(); + *(uint32_t *)buf = usbh->rootport.lld_status | (usbh->rootport.lld_c_status << 16); + osalOsRescheduleS(); + osalSysUnlock(); + break; + + case SetHubFeature: + chDbgAssert(0, "unsupported"); + break; + + case SetPortFeature: + chDbgAssert(windex == 1, "invalid windex"); + + switch (wvalue) { + case USBH_PORT_FEAT_TEST: + case USBH_PORT_FEAT_SUSPEND: + case USBH_PORT_FEAT_POWER: + chDbgAssert(0, "unimplemented"); /* TODO */ + break; + + case USBH_PORT_FEAT_RESET: { + osalSysLock(); + stm32_otg_t *const otg = usbh->otg; + uint32_t hprt; + otg->PCGCCTL = 0; + hprt = otg->HPRT; + /* note: writing PENA = 1 actually disables the port */ + hprt &= ~(HPRT_PSUSP | HPRT_PENA | HPRT_PCDET | HPRT_PENCHNG | HPRT_POCCHNG ); + otg->HPRT = hprt | HPRT_PRST; + osalThreadSleepS(MS2ST(60)); + otg->HPRT = hprt; + usbh->rootport.lld_c_status |= USBH_PORTSTATUS_C_RESET; + osalOsRescheduleS(); + osalSysUnlock(); + } break; + + case USBH_PORT_FEAT_INDICATOR: + chDbgAssert(0, "unsupported"); + break; + + default: + osalDbgAssert(0, "invalid wvalue"); + break; + } + break; + + default: + osalDbgAssert(0, "invalid typereq"); + break; + } + + return USBH_URBSTATUS_OK; +} + +uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh) { + osalSysLock(); + if (usbh->rootport.lld_c_status) { + osalOsRescheduleS(); + osalSysUnlock(); + return 1 << 1; + } + osalOsRescheduleS(); + osalSysUnlock(); + return 0; +} + + +#endif diff --git a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h index e8da2ac..e8df749 100644 --- a/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.h +++ b/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.h @@ -1,153 +1,153 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#ifndef USBH_LLD_H_
-#define USBH_LLD_H_
-
-#include "hal.h"
-
-#if HAL_USE_USBH
-
-#include "osal.h"
-#include "stm32_otg.h"
-
-/* TODO:
- *
- * - Implement ISO/INT OUT and test
- * - Consider DMA mode for OTG_HS, consider external PHY for HS.
- * - Implement a data pump thread, so we don't have to copy data from the ISR
- * This might be a bad idea for small endpoint packet sizes (the context switch
- * could be longer than the copy)
- */
-
-typedef enum {
- USBH_LLD_CTRLPHASE_SETUP,
- USBH_LLD_CTRLPHASE_DATA,
- USBH_LLD_CTRLPHASE_STATUS
-} usbh_lld_ctrlphase_t;
-
-typedef enum {
- USBH_LLD_HALTREASON_NONE,
- USBH_LLD_HALTREASON_XFRC,
- USBH_LLD_HALTREASON_NAK,
- USBH_LLD_HALTREASON_STALL,
- USBH_LLD_HALTREASON_ERROR,
- USBH_LLD_HALTREASON_ABORT
-} usbh_lld_halt_reason_t;
-
-
-typedef struct stm32_hc_management {
- struct list_head node;
-
- stm32_otg_host_chn_t *hc;
- volatile uint32_t *fifo;
- usbh_ep_t *ep;
- uint16_t haintmsk;
- usbh_lld_halt_reason_t halt_reason;
-} stm32_hc_management_t;
-
-
-#define _usbhdriver_ll_data \
- stm32_otg_t *otg; \
- /* channels */ \
- uint8_t channels_number; \
- stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \
- struct list_head ch_free[2]; \
- /* Enpoints being processed */ \
- struct list_head ep_active_lists[4]; \
- /* Pending endpoints */ \
- struct list_head ep_pending_lists[4];
-
-
-#define _usbh_ep_ll_data \
- struct list_head *active_list; /* shortcut to ep list */ \
- struct list_head *pending_list; /* shortcut to ep list */ \
- struct list_head urb_list; /* list of URBs queued in this EP */ \
- struct list_head node; /* this EP */ \
- uint32_t hcintmsk; \
- uint32_t hcchar; \
- uint32_t dt_mask; /* data-toggle mask */ \
- /* current transfer */ \
- struct { \
- stm32_hc_management_t *hcm; /* assigned channel */ \
- uint32_t len; /* this transfer's total length */ \
- uint8_t *buf; /* this transfer's buffer */ \
- uint32_t partial; /* this transfer's partial length */\
- uint16_t packets; /* packets allocated */ \
- union { \
- uint32_t frame_counter; /* frame counter (for INT) */ \
- usbh_lld_ctrlphase_t ctrl_phase; /* control phase (for CTRL) */ \
- } u; \
- uint8_t error_count; /* error count */ \
- } xfer;
-
-
-
-
-
-#define _usbh_port_ll_data \
- uint16_t lld_c_status; \
- uint16_t lld_status;
-
-#define _usbh_device_ll_data
-
-#define _usbh_hub_ll_data
-
-#define _usbh_urb_ll_data \
- struct list_head node; \
- bool queued;
-
-
-#define usbh_lld_urb_object_init(urb) \
- do { \
- osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \
- "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \
- urb->queued = FALSE; \
- } while (0)
-
-
-#define usbh_lld_urb_object_reset(urb) \
- do { \
- osalDbgAssert(urb->queued == FALSE, "wrong state"); \
- osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \
- "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \
- } while (0)
-
-
-
-void usbh_lld_init(void);
-void usbh_lld_start(USBHDriver *usbh);
-void usbh_lld_ep_object_init(usbh_ep_t *ep);
-void usbh_lld_ep_open(usbh_ep_t *ep);
-void usbh_lld_ep_close(usbh_ep_t *ep);
-void usbh_lld_urb_submit(usbh_urb_t *urb);
-bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status);
-usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest,
- uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf);
-uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh);
-
-#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0);
-
-#ifdef __IAR_SYSTEMS_ICC__
-#define USBH_LLD_DEFINE_BUFFER(type, name) type name
-#else
-#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4)))
-#endif
-
-#endif
-
-#endif /* USBH_LLD_H_ */
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef USBH_LLD_H_ +#define USBH_LLD_H_ + +#include "hal.h" + +#if HAL_USE_USBH + +#include "osal.h" +#include "stm32_otg.h" + +/* TODO: + * + * - Implement ISO/INT OUT and test + * - Consider DMA mode for OTG_HS, consider external PHY for HS. + * - Implement a data pump thread, so we don't have to copy data from the ISR + * This might be a bad idea for small endpoint packet sizes (the context switch + * could be longer than the copy) + */ + +typedef enum { + USBH_LLD_CTRLPHASE_SETUP, + USBH_LLD_CTRLPHASE_DATA, + USBH_LLD_CTRLPHASE_STATUS +} usbh_lld_ctrlphase_t; + +typedef enum { + USBH_LLD_HALTREASON_NONE, + USBH_LLD_HALTREASON_XFRC, + USBH_LLD_HALTREASON_NAK, + USBH_LLD_HALTREASON_STALL, + USBH_LLD_HALTREASON_ERROR, + USBH_LLD_HALTREASON_ABORT +} usbh_lld_halt_reason_t; + + +typedef struct stm32_hc_management { + struct list_head node; + + stm32_otg_host_chn_t *hc; + volatile uint32_t *fifo; + usbh_ep_t *ep; + uint16_t haintmsk; + usbh_lld_halt_reason_t halt_reason; +} stm32_hc_management_t; + + +#define _usbhdriver_ll_data \ + stm32_otg_t *otg; \ + /* channels */ \ + uint8_t channels_number; \ + stm32_hc_management_t channels[STM32_OTG2_CHANNELS_NUMBER]; \ + struct list_head ch_free[2]; \ + /* Enpoints being processed */ \ + struct list_head ep_active_lists[4]; \ + /* Pending endpoints */ \ + struct list_head ep_pending_lists[4]; + + +#define _usbh_ep_ll_data \ + struct list_head *active_list; /* shortcut to ep list */ \ + struct list_head *pending_list; /* shortcut to ep list */ \ + struct list_head urb_list; /* list of URBs queued in this EP */ \ + struct list_head node; /* this EP */ \ + uint32_t hcintmsk; \ + uint32_t hcchar; \ + uint32_t dt_mask; /* data-toggle mask */ \ + /* current transfer */ \ + struct { \ + stm32_hc_management_t *hcm; /* assigned channel */ \ + uint32_t len; /* this transfer's total length */ \ + uint8_t *buf; /* this transfer's buffer */ \ + uint32_t partial; /* this transfer's partial length */\ + uint16_t packets; /* packets allocated */ \ + union { \ + uint32_t frame_counter; /* frame counter (for INT) */ \ + usbh_lld_ctrlphase_t ctrl_phase; /* control phase (for CTRL) */ \ + } u; \ + uint8_t error_count; /* error count */ \ + } xfer; + + + + + +#define _usbh_port_ll_data \ + uint16_t lld_c_status; \ + uint16_t lld_status; + +#define _usbh_device_ll_data + +#define _usbh_hub_ll_data + +#define _usbh_urb_ll_data \ + struct list_head node; \ + bool queued; + + +#define usbh_lld_urb_object_init(urb) \ + do { \ + osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ + "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ + urb->queued = FALSE; \ + } while (0) + + +#define usbh_lld_urb_object_reset(urb) \ + do { \ + osalDbgAssert(urb->queued == FALSE, "wrong state"); \ + osalDbgAssert(((uint32_t)urb->buff & 3) == 0, \ + "use USBH_DEFINE_BUFFER() to declare the IO buffers"); \ + } while (0) + + + +void usbh_lld_init(void); +void usbh_lld_start(USBHDriver *usbh); +void usbh_lld_ep_object_init(usbh_ep_t *ep); +void usbh_lld_ep_open(usbh_ep_t *ep); +void usbh_lld_ep_close(usbh_ep_t *ep); +void usbh_lld_urb_submit(usbh_urb_t *urb); +bool usbh_lld_urb_abort(usbh_urb_t *urb, usbh_urbstatus_t status); +usbh_urbstatus_t usbh_lld_root_hub_request(USBHDriver *usbh, uint8_t bmRequestType, uint8_t bRequest, + uint16_t wvalue, uint16_t windex, uint16_t wlength, uint8_t *buf); +uint8_t usbh_lld_roothub_get_statuschange_bitmap(USBHDriver *usbh); + +#define usbh_lld_epreset(ep) do {(ep)->dt_mask = HCTSIZ_DPID_DATA0;} while (0); + +#ifdef __IAR_SYSTEMS_ICC__ +#define USBH_LLD_DEFINE_BUFFER(type, name) type name +#else +#define USBH_LLD_DEFINE_BUFFER(type, name) type name __attribute__((aligned(4))) +#endif + +#endif + +#endif /* USBH_LLD_H_ */ diff --git a/os/hal/ports/STM32/STM32F0xx/platform.mk b/os/hal/ports/STM32/STM32F0xx/platform.mk index 1dff83a..c796984 100644 --- a/os/hal/ports/STM32/STM32F0xx/platform.mk +++ b/os/hal/ports/STM32/STM32F0xx/platform.mk @@ -1,7 +1,7 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F0xx/platform.mk -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c \ +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c \ PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1 \ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \ diff --git a/os/hal/ports/STM32/STM32F3xx/platform.mk b/os/hal/ports/STM32/STM32F3xx/platform.mk index e98de86..baa7578 100644 --- a/os/hal/ports/STM32/STM32F3xx/platform.mk +++ b/os/hal/ports/STM32/STM32F3xx/platform.mk @@ -1,8 +1,8 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F3xx/platform.mk -PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \ - ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c +PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c \ + ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1 \ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1 \ diff --git a/os/hal/ports/STM32/STM32F4xx/platform.mk b/os/hal/ports/STM32/STM32F4xx/platform.mk index 5ffc9dd..b78df83 100644 --- a/os/hal/ports/STM32/STM32F4xx/platform.mk +++ b/os/hal/ports/STM32/STM32F4xx/platform.mk @@ -1,15 +1,15 @@ include ${CHIBIOS}/os/hal/ports/STM32/STM32F4xx/platform.mk
-PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1/stm32_dma2d.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/nand_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/fsmc_sram.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/stm32_ltdc.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/eicu_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/timcap_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1/usbh_lld.c \
- ${CHIBIOS_CONTRIB}/os/hal/src/fsmc_sdram.c \
- ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/crc_lld.c
+PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1/hal_stm32_dma2d.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_nand_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1/hal_fsmc_sram.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/LTDCv1/hal_stm32_ltdc.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_eicu_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/TIMv1/hal_timcap_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/USBHv1/hal_usbh_lld.c \
+ ${CHIBIOS_CONTRIB}/os/hal/src/hal_fsmc_sdram.c \
+ ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/CRCv1/hal_crc_lld.c
PLATFORMINC += ${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/DMA2Dv1 \
${CHIBIOS_CONTRIB}/os/hal/ports/STM32/LLD/FSMCv1 \
diff --git a/os/hal/src/crc.c b/os/hal/src/hal_crc.c index 63799e4..63799e4 100644 --- a/os/hal/src/crc.c +++ b/os/hal/src/hal_crc.c diff --git a/os/hal/src/ee24xx.c b/os/hal/src/hal_ee24xx.c index c89635f..632ffbb 100644 --- a/os/hal/src/ee24xx.c +++ b/os/hal/src/hal_ee24xx.c @@ -42,7 +42,7 @@ Note: being written to the next page as might be expected. *********************************************************************/ -#include "ee24xx.h" +#include "hal_ee24xx.h" #include <string.h> #if (defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE24XX) || defined(__DOXYGEN__) diff --git a/os/hal/src/ee25xx.c b/os/hal/src/hal_ee25xx.c index 07f4373..102aef8 100644 --- a/os/hal/src/ee25xx.c +++ b/os/hal/src/hal_ee25xx.c @@ -42,7 +42,7 @@ Note: being written to the next page as might be expected. *********************************************************************/ -#include "ee25xx.h" +#include "hal_ee25xx.h" #include <string.h> #if (defined(HAL_USE_EEPROM) && HAL_USE_EEPROM && EEPROM_USE_EE25XX) || defined(__DOXYGEN__) diff --git a/os/hal/src/eeprom.c b/os/hal/src/hal_eeprom.c index 60d90ed..f77d616 100644 --- a/os/hal/src/eeprom.c +++ b/os/hal/src/hal_eeprom.c @@ -26,7 +26,7 @@ The work is provided "as is" without warranty of any kind, neither express nor implied. */ -#include "eeprom.h" +#include "hal_eeprom.h" #include <string.h> #if defined(HAL_USE_EEPROM) && HAL_USE_EEPROM diff --git a/os/hal/src/eicu.c b/os/hal/src/hal_eicu.c index f75c58b..f75c58b 100644 --- a/os/hal/src/eicu.c +++ b/os/hal/src/hal_eicu.c diff --git a/os/hal/src/nand.c b/os/hal/src/hal_nand.c index 24dd6de..24dd6de 100644 --- a/os/hal/src/nand.c +++ b/os/hal/src/hal_nand.c diff --git a/os/hal/src/onewire.c b/os/hal/src/hal_onewire.c index 85f0fdc..85f0fdc 100644 --- a/os/hal/src/onewire.c +++ b/os/hal/src/hal_onewire.c diff --git a/os/hal/src/rng.c b/os/hal/src/hal_rng.c index 5ff6d2d..5ff6d2d 100644 --- a/os/hal/src/rng.c +++ b/os/hal/src/hal_rng.c diff --git a/os/hal/src/timcap.c b/os/hal/src/hal_timcap.c index 6ee97ad..a352490 100644 --- a/os/hal/src/timcap.c +++ b/os/hal/src/hal_timcap.c @@ -26,7 +26,7 @@ * @{ */ -#include "timcap.h" +#include "hal_timcap.h" #if HAL_USE_TIMCAP || defined(__DOXYGEN__) diff --git a/os/hal/src/usbh.c b/os/hal/src/hal_usbh.c index 3bdbac3..1caa183 100644 --- a/os/hal/src/usbh.c +++ b/os/hal/src/hal_usbh.c @@ -1,1395 +1,1395 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-
-#if HAL_USE_USBH
-
-#include "usbh/dev/hub.h"
-#include "usbh/internal.h"
-#include <string.h>
-
-#if USBH_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBH_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBH_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBH_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-#if STM32_USBH_USE_OTG1
-USBHDriver USBHD1;
-#endif
-#if STM32_USBH_USE_OTG2
-USBHDriver USBHD2;
-#endif
-
-
-static void _classdriver_process_device(usbh_device_t *dev);
-static bool _classdriver_load(usbh_device_t *dev, uint8_t class,
- uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem);
-
-
-/*===========================================================================*/
-/* Checks. */
-/*===========================================================================*/
-
-static inline void _check_dev(usbh_device_t *dev) {
- osalDbgCheck(dev);
- //TODO: add more checks.
-}
-
-static inline void _check_ep(usbh_ep_t *ep) {
- osalDbgCheck(ep != 0);
- _check_dev(ep->device);
- osalDbgCheck(ep->type <= 3);
- //TODO: add more checks.
-}
-
-static inline void _check_urb(usbh_urb_t *urb) {
- osalDbgCheck(urb != 0);
- _check_ep(urb->ep);
- osalDbgCheck((urb->buff != NULL) || (urb->requestedLength == 0));
- //TODO: add more checks.
-}
-
-/*===========================================================================*/
-/* Main driver API. */
-/*===========================================================================*/
-
-void usbhObjectInit(USBHDriver *usbh) {
- memset(usbh, 0, sizeof(*usbh));
- usbh->status = USBH_STATUS_STOPPED;
-#if HAL_USBH_USE_HUB
- INIT_LIST_HEAD(&usbh->hubs);
- _usbhub_port_object_init(&usbh->rootport, usbh, 0, 1);
-#else
- _usbhub_port_object_init(&usbh->rootport, usbh, 1);
-#endif
-}
-
-void usbhInit(void) {
-#if HAL_USBH_USE_HUB
- uint8_t i;
- for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) {
- usbhhubObjectInit(&USBHHUBD[i]);
- }
-#endif
- usbh_lld_init();
-}
-
-void usbhStart(USBHDriver *usbh) {
- usbDbgInit(usbh);
-
- osalSysLock();
- osalDbgAssert((usbh->status == USBH_STATUS_STOPPED) || (usbh->status == USBH_STATUS_STARTED),
- "invalid state");
- usbh_lld_start(usbh);
- usbh->status = USBH_STATUS_STARTED;
- osalOsRescheduleS();
- osalSysUnlock();
-}
-
-
-void usbhStop(USBHDriver *usbh) {
- //TODO: implement
- (void)usbh;
-}
-void usbhSuspend(USBHDriver *usbh) {
- //TODO: implement
- (void)usbh;
-}
-void usbhResume(USBHDriver *usbh) {
- //TODO: implement
- (void)usbh;
-}
-
-/*===========================================================================*/
-/* Endpoint API. */
-/*===========================================================================*/
-
-void usbhEPObjectInit(usbh_ep_t *ep, usbh_device_t *dev, const usbh_endpoint_descriptor_t *desc) {
- osalDbgCheck(ep);
- _check_dev(dev);
- osalDbgCheck(desc);
-
- memset(ep, 0, sizeof(*ep));
- ep->device = dev;
- ep->wMaxPacketSize = desc->wMaxPacketSize;
- ep->address = desc->bEndpointAddress & 0x0F;
- ep->type = (usbh_eptype_t) (desc->bmAttributes & 0x03);
- if (ep->type != USBH_EPTYPE_CTRL) {
- ep->in = (desc->bEndpointAddress & 0x80) ? TRUE : FALSE;
- }
- ep->bInterval = desc->bInterval;
-
- /* low-level part */
- usbh_lld_ep_object_init(ep);
-
- ep->status = USBH_EPSTATUS_CLOSED;
-}
-
-
-static void _ep0_object_init(usbh_device_t *dev, uint16_t wMaxPacketSize) {
- const usbh_endpoint_descriptor_t ep0_descriptor = {
- 7, //bLength
- 5, //bDescriptorType
- 0, //bEndpointAddress
- 0, //bmAttributes
- wMaxPacketSize,
- 0, //bInterval
- };
- usbhEPObjectInit(&dev->ctrl, dev, &ep0_descriptor);
- usbhEPSetName(&dev->ctrl, "DEV[CTRL]");
-}
-
-
-/*===========================================================================*/
-/* URB API. */
-/*===========================================================================*/
-
-void usbhURBObjectInit(usbh_urb_t *urb, usbh_ep_t *ep, usbh_completion_cb callback,
- void *user, void *buff, uint32_t len) {
-
- osalDbgCheck(urb != 0);
- _check_ep(ep);
-
- /* initialize the common part: */
- urb->ep = ep;
- urb->callback = callback;
- urb->userData = user;
- urb->buff = buff;
- urb->requestedLength = len;
- urb->actualLength = 0;
- urb->status = USBH_URBSTATUS_INITIALIZED;
- urb->waitingThread = 0;
- urb->abortingThread = 0;
-
- /* initialize the ll part: */
- usbh_lld_urb_object_init(urb);
-}
-
-void usbhURBObjectResetI(usbh_urb_t *urb) {
- osalDbgAssert(!usbhURBIsBusy(urb), "invalid status");
-
- osalDbgCheck((urb->waitingThread == 0) && (urb->abortingThread == 0));
-
- urb->actualLength = 0;
- urb->status = USBH_URBSTATUS_INITIALIZED;
-
- /* reset the ll part: */
- usbh_lld_urb_object_reset(urb);
-}
-
-void usbhURBSubmitI(usbh_urb_t *urb) {
- osalDbgCheckClassI();
- _check_urb(urb);
- osalDbgAssert(urb->status == USBH_URBSTATUS_INITIALIZED, "invalid status");
- usbh_ep_t *const ep = urb->ep;
- if (ep->status == USBH_EPSTATUS_HALTED) {
- _usbh_urb_completeI(urb, USBH_URBSTATUS_STALL);
- return;
- }
- if (ep->status != USBH_EPSTATUS_OPEN) {
- _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED);
- return;
- }
- if (!(usbhDeviceGetPort(ep->device)->status & USBH_PORTSTATUS_ENABLE)) {
- _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED);
- return;
- }
- urb->status = USBH_URBSTATUS_PENDING;
- usbh_lld_urb_submit(urb);
-}
-
-bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalDbgCheckClassI();
- _check_urb(urb);
-
- switch (urb->status) {
-/* case USBH_URBSTATUS_UNINITIALIZED:
- * case USBH_URBSTATUS_INITIALIZED:
- * case USBH_URBSTATUS_ERROR:
- * case USBH_URBSTATUS_TIMEOUT:
- * case USBH_URBSTATUS_CANCELLED:
- * case USBH_URBSTATUS_STALL:
- * case USBH_URBSTATUS_DISCONNECTED:
- * case USBH_URBSTATUS_OK: */
- default:
- /* already finished */
- _usbh_urb_completeI(urb, status);
- return TRUE;
-
-// case USBH_URBSTATUS_QUEUED:
- case USBH_URBSTATUS_PENDING:
- return usbh_lld_urb_abort(urb, status);
- }
-}
-
-void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalDbgCheckClassS();
- _check_urb(urb);
-
- if (_usbh_urb_abortI(urb, status) == FALSE) {
- uwarn("URB wasn't aborted immediately, suspend");
- osalThreadSuspendS(&urb->abortingThread);
- urb->abortingThread = 0;
- } else {
- osalOsRescheduleS();
- }
- uwarn("URB aborted");
-}
-
-bool usbhURBCancelI(usbh_urb_t *urb) {
- return _usbh_urb_abortI(urb, USBH_URBSTATUS_CANCELLED);
-}
-
-void usbhURBCancelAndWaitS(usbh_urb_t *urb) {
- _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_CANCELLED);
-}
-
-msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout) {
- msg_t ret;
-
- osalDbgCheckClassS();
- _check_urb(urb);
-
- switch (urb->status) {
- case USBH_URBSTATUS_INITIALIZED:
- case USBH_URBSTATUS_PENDING:
-// case USBH_URBSTATUS_QUEUED:
- ret = osalThreadSuspendTimeoutS(&urb->waitingThread, timeout);
- urb->waitingThread = 0;
- break;
-
- case USBH_URBSTATUS_OK:
- ret = MSG_OK;
- osalOsRescheduleS();
- break;
-
-/* case USBH_URBSTATUS_UNINITIALIZED:
- * case USBH_URBSTATUS_ERROR:
- * case USBH_URBSTATUS_TIMEOUT:
- * case USBH_URBSTATUS_CANCELLED:
- * case USBH_URBSTATUS_STALL:
- * case USBH_URBSTATUS_DISCONNECTED: */
- default:
- ret = MSG_RESET;
- osalOsRescheduleS();
- break;
- }
- return ret;
-}
-
-msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout) {
- msg_t ret;
-
- osalDbgCheckClassS();
- _check_urb(urb);
-
- usbhURBSubmitI(urb);
- ret = usbhURBWaitTimeoutS(urb, timeout);
- if (ret == MSG_TIMEOUT)
- _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_TIMEOUT);
-
- return ret;
-}
-
-static inline msg_t _wakeup_message(usbh_urbstatus_t status) {
- if (status == USBH_URBSTATUS_OK) return MSG_OK;
- if (status == USBH_URBSTATUS_TIMEOUT) return MSG_TIMEOUT;
- return MSG_RESET;
-}
-
-void _usbh_urb_completeI(usbh_urb_t *urb, usbh_urbstatus_t status) {
- osalDbgCheckClassI();
- _check_urb(urb);
- urb->status = status;
- osalThreadResumeI(&urb->waitingThread, _wakeup_message(status));
- osalThreadResumeI(&urb->abortingThread, MSG_RESET);
- if (urb->callback)
- urb->callback(urb);
-}
-
-/*===========================================================================*/
-/* Synchronous API. */
-/*===========================================================================*/
-
-usbh_urbstatus_t usbhBulkTransfer(usbh_ep_t *ep,
- void *data,
- uint32_t len,
- uint32_t *actual_len,
- systime_t timeout) {
-
- osalDbgCheck(ep != NULL);
- osalDbgCheck((data != NULL) || (len == 0));
- osalDbgAssert(ep->type == USBH_EPTYPE_BULK, "wrong ep");
-
- usbh_urb_t urb;
- usbhURBObjectInit(&urb, ep, 0, 0, data, len);
-
- osalSysLock();
- usbhURBSubmitAndWaitS(&urb, timeout);
- osalSysUnlock();
-
- if (actual_len != NULL)
- *actual_len = urb.actualLength;
-
- return urb.status;
-}
-
-usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev,
- const usbh_control_request_t *req,
- uint8_t *buff,
- uint32_t *actual_len,
- systime_t timeout) {
-
- _check_dev(dev);
- osalDbgCheck(req != NULL);
-
- usbh_urb_t urb;
-
- usbhURBObjectInit(&urb, &dev->ctrl, 0, 0, buff, req->wLength);
- urb.setup_buff = req;
-
- osalSysLock();
- usbhURBSubmitAndWaitS(&urb, timeout);
- osalSysUnlock();
-
- if (actual_len != NULL)
- *actual_len = urb.actualLength;
-
- return urb.status;
-}
-
-usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev,
- uint8_t bmRequestType,
- uint8_t bRequest,
- uint16_t wValue,
- uint16_t wIndex,
- uint16_t wLength,
- uint8_t *buff) {
-
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
- bmRequestType,
- bRequest,
- wValue,
- wIndex,
- wLength
- };
- return usbhControlRequestExtended(dev, &req, buff, NULL, MS2ST(1000));
-}
-
-/*===========================================================================*/
-/* Standard request helpers. */
-/*===========================================================================*/
-
-#define USBH_GET_DESCRIPTOR(type, value, index) \
- USBH_STANDARDIN(type, \
- USBH_REQ_GET_DESCRIPTOR, \
- value, \
- index) \
-
-#define USBH_GETDEVICEDESCRIPTOR \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_DEVICE << 8) | 0, 0)
-
-#define USBH_GETCONFIGURATIONDESCRIPTOR(index) \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_CONFIG << 8) | index, 0)
-
-#define USBH_GETSTRINGDESCRIPTOR(index, langID) \
- USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_STRING << 8) | index, langID)
-
-bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev,
- uint16_t wLength,
- uint8_t *buf) {
- usbh_device_descriptor_t *desc;
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETDEVICEDESCRIPTOR, wLength, buf);
- desc = (usbh_device_descriptor_t *)buf;
- if ((ret != USBH_URBSTATUS_OK)
- || (desc->bLength != USBH_DT_DEVICE_SIZE)
- || (desc->bDescriptorType != USBH_DT_DEVICE)) {
- return HAL_FAILED;
- }
- return HAL_SUCCESS;
-}
-
-bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev,
- uint8_t index,
- uint16_t wLength,
- uint8_t *buf) {
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETCONFIGURATIONDESCRIPTOR(index), wLength, buf);
- usbh_config_descriptor_t *const desc = (usbh_config_descriptor_t *)buf;
- if ((ret != USBH_URBSTATUS_OK)
- || (desc->bLength < USBH_DT_CONFIG_SIZE)
- || (desc->bDescriptorType != USBH_DT_CONFIG)) {
- return HAL_FAILED;
- }
- return HAL_SUCCESS;
-}
-
-bool usbhStdReqGetStringDescriptor(usbh_device_t *dev,
- uint8_t index,
- uint16_t langID,
- uint16_t wLength,
- uint8_t *buf) {
-
- osalDbgAssert(wLength >= USBH_DT_STRING_SIZE, "wrong size");
- usbh_string_descriptor_t *desc = (usbh_string_descriptor_t *)buf;
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETSTRINGDESCRIPTOR(index, langID), wLength, buf);
- if ((ret != USBH_URBSTATUS_OK)
- || (desc->bLength < USBH_DT_STRING_SIZE)
- || (desc->bDescriptorType != USBH_DT_STRING)) {
- return HAL_FAILED;
- }
- return HAL_SUCCESS;
-}
-
-
-
-#define USBH_SET_INTERFACE(interface, alt) \
- USBH_STANDARDOUT(USBH_REQTYPE_INTERFACE, \
- USBH_REQ_SET_INTERFACE, \
- alt, \
- interface) \
-
-#define USBH_GET_INTERFACE(interface) \
- USBH_STANDARDIN(USBH_REQTYPE_INTERFACE, \
- USBH_REQ_GET_INTERFACE, \
- 0, \
- interface) \
-
-bool usbhStdReqSetInterface(usbh_device_t *dev,
- uint8_t bInterfaceNumber,
- uint8_t bAlternateSetting) {
-
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_SET_INTERFACE(bInterfaceNumber, bAlternateSetting), 0, NULL);
- if (ret != USBH_URBSTATUS_OK)
- return HAL_FAILED;
-
- return HAL_SUCCESS;
-}
-
-bool usbhStdReqGetInterface(usbh_device_t *dev,
- uint8_t bInterfaceNumber,
- uint8_t *bAlternateSetting) {
-
- USBH_DEFINE_BUFFER(uint8_t, alt);
-
- usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GET_INTERFACE(bInterfaceNumber), 1, &alt);
- if (ret != USBH_URBSTATUS_OK)
- return HAL_FAILED;
-
- *bAlternateSetting = alt;
- return HAL_SUCCESS;
-}
-
-
-/*===========================================================================*/
-/* Device-related functions. */
-/*===========================================================================*/
-
-static uint8_t _find_address(USBHDriver *host) {
- uint8_t addr, i, j;
- for (i = 0; i < sizeof_array(host->address_bitmap); i++) {
- addr = host->address_bitmap[i];
- for (j = 0; j < 8; j++) {
- if ((addr & (1 << j)) == 0) {
- //found:
- addr = i * 8 + j + 1;
- host->address_bitmap[i] |= (1 << j);
- return addr;
- }
- }
- }
- return 0;
-}
-
-static void _free_address(USBHDriver *host, uint8_t addr) {
- uinfof("Free address %d", addr);
- host->address_bitmap[addr / 8] &= ~(1 << ((addr - 1) & 7));
-}
-
-static void _device_initialize(usbh_device_t *dev, usbh_devspeed_t speed) {
- dev->address = 0;
- dev->speed = speed;
- dev->status = USBH_DEVSTATUS_DEFAULT;
- dev->langID0 = 0;
- dev->keepFullCfgDesc = 0;
- _ep0_object_init(dev, 64);
-}
-
-static bool _device_setaddress(usbh_device_t *dev, uint8_t address) {
- usbh_urbstatus_t ret = usbhControlRequest(dev,
- USBH_STANDARDOUT(USBH_REQTYPE_DEVICE, USBH_REQ_SET_ADDRESS, address, 0),
- 0,
- 0);
- if (ret != USBH_URBSTATUS_OK)
- return HAL_FAILED;
-
- dev->address = address;
- return HAL_SUCCESS;
-}
-
-static inline bool _device_read_basic_cfgdesc(usbh_device_t *dev, uint8_t bConfiguration) {
- /* get configuration descriptor */
- return usbhStdReqGetConfigurationDescriptor(dev, bConfiguration,
- sizeof(dev->basicConfigDesc), (uint8_t *)&dev->basicConfigDesc);
-}
-
-static void _device_read_full_cfgdesc(usbh_device_t *dev, uint8_t bConfiguration) {
- _check_dev(dev);
-
- uint8_t i;
-
- if (dev->fullConfigurationDescriptor != NULL) {
- chHeapFree(dev->fullConfigurationDescriptor);
- }
-
- dev->fullConfigurationDescriptor =
- (uint8_t *)chHeapAlloc(0, dev->basicConfigDesc.wTotalLength);
-
- if (!dev->fullConfigurationDescriptor)
- return;
-
- for (i = 0; i < 3; i++) {
- if (usbhStdReqGetConfigurationDescriptor(dev, bConfiguration,
- dev->basicConfigDesc.wTotalLength,
- dev->fullConfigurationDescriptor) == HAL_SUCCESS) {
- return;
- }
- osalThreadSleepMilliseconds(200);
- }
-
- /* error */
- chHeapFree(dev->fullConfigurationDescriptor);
- dev->fullConfigurationDescriptor = NULL;
-}
-
-static void _device_free_full_cfgdesc(usbh_device_t *dev) {
- osalDbgCheck(dev);
- if (dev->fullConfigurationDescriptor != NULL) {
- chHeapFree(dev->fullConfigurationDescriptor);
- dev->fullConfigurationDescriptor = NULL;
- }
-}
-
-
-#define USBH_SET_CONFIGURATION(type, value, index) \
- USBH_STANDARDOUT(type, \
- USBH_REQ_SET_CONFIGURATION, \
- value, \
- index) \
-
-#define USBH_SETDEVICECONFIGURATION(index) \
- USBH_SET_CONFIGURATION(USBH_REQTYPE_DEVICE, index, 0)
-
-
-static bool _device_set_configuration(usbh_device_t *dev, uint8_t configuration) {
- usbh_urbstatus_t ret = usbhControlRequest(dev,
- USBH_SETDEVICECONFIGURATION(configuration),
- 0,
- 0);
- if (ret != USBH_URBSTATUS_OK)
- return HAL_FAILED;
- return HAL_SUCCESS;
-}
-
-static bool _device_configure(usbh_device_t *dev, uint8_t bConfiguration) {
- uint8_t i;
-
- uinfof("Reading basic configuration descriptor %d", bConfiguration);
- for (i = 0; i < 3; i++) {
- if (!_device_read_basic_cfgdesc(dev, bConfiguration))
- break;
- }
-
- if (i == 3) {
- uerrf("Could not read basic configuration descriptor %d; "
- "won't configure device", bConfiguration);
- return HAL_FAILED;
- }
-
- uinfof("Selecting configuration %d", bConfiguration);
- for (i = 0; i < 3; i++) {
- if (!_device_set_configuration(dev, dev->basicConfigDesc.bConfigurationValue)) {
- /* TODO: check if correctly configured using GET_CONFIGURATION */
- dev->status = USBH_DEVSTATUS_CONFIGURED;
- dev->bConfiguration = bConfiguration;
-
- uinfo("Device configured.");
- return HAL_SUCCESS;
- }
- }
-
- return HAL_FAILED;
-}
-
-static bool _device_enumerate(usbh_device_t *dev) {
-
- uinfo("Enumerate.");
- uinfo("Get first 8 bytes of device descriptor");
-
- /* get first 8 bytes of device descriptor */
- if (usbhStdReqGetDeviceDescriptor(dev, 8, (uint8_t *)&dev->devDesc)) {
- uerr("Error");
- return HAL_FAILED;
- }
-
- uinfof("Configure bMaxPacketSize0 = %d", dev->devDesc.bMaxPacketSize0);
- /* configure EP0 wMaxPacketSize */
- usbhEPClose(&dev->ctrl);
- _ep0_object_init(dev, dev->devDesc.bMaxPacketSize0);
- usbhEPOpen(&dev->ctrl);
-
- uint8_t addr = _find_address(dev->host);
- if (addr == 0) {
- uerr("No free addresses found");
- return HAL_FAILED;
- }
-
- /* set device address */
- uinfof("Set device address: %d", addr);
- if (_device_setaddress(dev, addr)) {
- uerr("Error");
- _free_address(dev->host, addr);
- return HAL_FAILED;
- }
-
- /* update EP because of the address change */
- usbhEPClose(&dev->ctrl);
- _ep0_object_init(dev, dev->devDesc.bMaxPacketSize0);
- usbhEPOpen(&dev->ctrl);
-
- uinfof("Wait stabilization...");
- osalThreadSleepMilliseconds(HAL_USBH_DEVICE_ADDRESS_STABILIZATION);
-
- /* address is set */
- dev->status = USBH_DEVSTATUS_ADDRESS;
-
- uinfof("Get full device desc");
- /* get full device descriptor */
- if (usbhStdReqGetDeviceDescriptor(dev, sizeof(dev->devDesc),
- (uint8_t *)&dev->devDesc)) {
- uerr("Error");
- _device_setaddress(dev, 0);
- _free_address(dev->host, addr);
- return HAL_FAILED;
- }
-
- uinfof("Enumeration finished.");
- return HAL_SUCCESS;
-}
-
-#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO
-void usbhDevicePrintInfo(usbh_device_t *dev) {
- USBH_DEFINE_BUFFER(char, str[64]);
- usbh_device_descriptor_t *const desc = &dev->devDesc;
-
- uinfo("----- Device info -----");
- uinfo("Device descriptor:");
- uinfof("\tUSBSpec=%04x, #configurations=%d, langID0=%04x",
- desc->bcdUSB,
- desc->bNumConfigurations,
- dev->langID0);
-
- uinfof("\tClass=%02x, Subclass=%02x, Protocol=%02x",
- desc->bDeviceClass,
- desc->bDeviceSubClass,
- desc->bDeviceProtocol);
-
- uinfof("\tVID=%04x, PID=%04x, Release=%04x",
- desc->idVendor,
- desc->idProduct,
- desc->bcdDevice);
-
- if (dev->langID0) {
- usbhDeviceReadString(dev, str, sizeof(str), desc->iManufacturer, dev->langID0);
- uinfof("\tManufacturer: %s", str);
- usbhDeviceReadString(dev, str, sizeof(str), desc->iProduct, dev->langID0);
- uinfof("\tProduct: %s", str);
- usbhDeviceReadString(dev, str, sizeof(str), desc->iSerialNumber, dev->langID0);
- uinfof("\tSerial Number: %s", str);
- }
-
- if (dev->status == USBH_DEVSTATUS_CONFIGURED) {
- uinfo("Configuration descriptor (partial):");
- usbh_config_descriptor_t *const cfg = &dev->basicConfigDesc;
- uinfof("\tbConfigurationValue=%d, Length=%d, #interfaces=%d",
- cfg->bConfigurationValue,
- cfg->wTotalLength,
- cfg->bNumInterfaces);
-
- uinfof("\tCurrent=%dmA", cfg->bMaxPower * 2);
- uinfof("\tSelfPowered=%d, RemoteWakeup=%d",
- cfg->bmAttributes & 0x40 ? 1 : 0,
- cfg->bmAttributes & 0x20 ? 1 : 0);
- if (dev->langID0) {
- usbhDeviceReadString(dev, str, sizeof(str), cfg->iConfiguration, dev->langID0);
- uinfof("\tName: %s", str);
- }
- }
-
- uinfo("----- End Device info -----");
-
-}
-
-void usbhDevicePrintConfiguration(const uint8_t *descriptor, uint16_t rem) {
- generic_iterator_t iep, icfg, ics;
- if_iterator_t iif;
-
- uinfo("----- Configuration info -----");
- uinfo("Configuration descriptor:");
- cfg_iter_init(&icfg, descriptor, rem);
- const usbh_config_descriptor_t *const cfgdesc = cfg_get(&icfg);
- uinfof("Configuration %d, #IFs=%d", cfgdesc->bConfigurationValue, cfgdesc->bNumInterfaces);
-
- for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
- const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
-
- uinfof(" Interface %d, alt=%d, #EPs=%d, "
- "Class=%02x, Subclass=%02x, Protocol=%02x",
- ifdesc->bInterfaceNumber, ifdesc->bAlternateSetting, ifdesc->bNumEndpoints,
- ifdesc->bInterfaceClass, ifdesc->bInterfaceSubClass, ifdesc->bInterfaceProtocol);
-
- for (cs_iter_init(&ics, (generic_iterator_t *)&iif); ics.valid; cs_iter_next(&ics)) {
- uinfof(" Class-Specific descriptor, Length=%d, Type=%02x",
- ics.curr[0], ics.curr[1]);
- }
-
- for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
- const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
-
- uinfof(" Endpoint descriptor, Address=%02x, Type=%d, MaxPacket=%d, Interval=%d",
- epdesc->bEndpointAddress,
- epdesc->bmAttributes & 3,
- epdesc->wMaxPacketSize,
- epdesc->bInterval);
-
- for (cs_iter_init(&ics, &iep); ics.valid; cs_iter_next(&ics)) {
- uinfof(" Class-Specific descriptor, Length=%d, Type=%02x",
- ics.curr[0], ics.curr[1]);
- }
- }
- }
- uinfo("----- End Configuration info -----");
-}
-#endif
-
-bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size,
- uint8_t index, uint16_t langID) {
-
- usbh_string_descriptor_t *const desc = (usbh_string_descriptor_t *)dest;
- osalDbgAssert(size >= 2, "wrong size");
-
- *dest = 0;
- if (index == 0)
- return HAL_SUCCESS;
- if (usbhStdReqGetStringDescriptor(dev, index, langID, size, (uint8_t *)dest))
- return HAL_FAILED;
- if (desc->bLength & 1)
- return HAL_FAILED;
- if (desc->bLength <= 2)
- return HAL_SUCCESS;
-
- uint8_t nchars = desc->bLength / 2; /* including the trailing 0 */
- if (size < nchars)
- nchars = size;
-
- char *src = (char *)&desc->wData[0];
- while (--nchars) {
- *dest++ = *src;
- src += 2;
- }
- *dest = 0;
- return HAL_SUCCESS;
-}
-
-
-
-
-/*===========================================================================*/
-/* Port processing functions. */
-/*===========================================================================*/
-
-static void _port_connected(usbh_port_t *port);
-
-static void _port_reset(usbh_port_t *port) {
- usbhhubControlRequest(port->device.host,
-#if HAL_USBH_USE_HUB
- port->hub,
-#endif
- USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
- USBH_REQ_SET_FEATURE,
- USBH_PORT_FEAT_RESET,
- port->number,
- 0,
- 0);
-}
-
-static void _port_update_status(usbh_port_t *port) {
- uint32_t stat;
- if (usbhhubControlRequest(port->device.host,
-#if HAL_USBH_USE_HUB
- port->hub,
-#endif
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER,
- USBH_REQ_GET_STATUS,
- 0,
- port->number,
- 4,
- (uint8_t *)&stat) != USBH_URBSTATUS_OK) {
- return;
- }
- port->status = stat & 0xffff;
- port->c_status |= stat >> 16;
-}
-
-static void _port_process_status_change(usbh_port_t *port) {
-
- _port_update_status(port);
-
- if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) {
- /* port connected status changed */
- port->c_status &= ~USBH_PORTSTATUS_C_CONNECTION;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_CONNECTION);
- if ((port->status & (USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE))
- == USBH_PORTSTATUS_CONNECTION) {
- if (port->device.status != USBH_DEVSTATUS_DISCONNECTED) {
- _usbh_port_disconnected(port);
- }
-
- /* connected, disabled */
- _port_connected(port);
- } else {
- /* disconnected */
- _usbh_port_disconnected(port);
- }
- }
-
- if (port->c_status & USBH_PORTSTATUS_C_RESET) {
- port->c_status &= ~USBH_PORTSTATUS_C_RESET;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_RESET);
- }
-
- if (port->c_status & USBH_PORTSTATUS_C_ENABLE) {
- port->c_status &= ~USBH_PORTSTATUS_C_ENABLE;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_ENABLE);
- }
-
- if (port->c_status & USBH_PORTSTATUS_C_OVERCURRENT) {
- port->c_status &= ~USBH_PORTSTATUS_C_OVERCURRENT;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_OVERCURRENT);
- }
-
- if (port->c_status & USBH_PORTSTATUS_C_SUSPEND) {
- port->c_status &= ~USBH_PORTSTATUS_C_SUSPEND;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_SUSPEND);
- }
-
-}
-
-
-static void _port_connected(usbh_port_t *port) {
- /* connected */
-
- systime_t start;
- uint8_t i;
- uint8_t retries;
- usbh_devspeed_t speed;
- USBH_DEFINE_BUFFER(usbh_string_descriptor_t, strdesc);
-
- uinfof("Port %d connected, wait debounce...", port->number);
-
- port->device.status = USBH_DEVSTATUS_ATTACHED;
-
- /* wait for attach de-bounce */
- osalThreadSleepMilliseconds(HAL_USBH_PORT_DEBOUNCE_TIME);
-
- /* check disconnection */
- _port_update_status(port);
- if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) {
- /* connection state changed; abort */
- goto abort;
- }
-
- port->device.status = USBH_DEVSTATUS_CONNECTED;
- retries = 3;
-
-reset:
- for (i = 0; i < 3; i++) {
- uinfo("Try reset...");
- port->c_status &= ~(USBH_PORTSTATUS_C_RESET | USBH_PORTSTATUS_C_ENABLE);
- _port_reset(port);
- osalThreadSleepMilliseconds(20); /* give it some time to reset (min. 10ms) */
- start = osalOsGetSystemTimeX();
- while (TRUE) {
- _port_update_status(port);
-
- /* check for disconnection */
- if (port->c_status & USBH_PORTSTATUS_C_CONNECTION)
- goto abort;
-
- /* check for reset completion */
- if (port->c_status & USBH_PORTSTATUS_C_RESET) {
- port->c_status &= ~USBH_PORTSTATUS_C_RESET;
- usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_RESET);
-
- if ((port->status & (USBH_PORTSTATUS_ENABLE | USBH_PORTSTATUS_CONNECTION))
- == (USBH_PORTSTATUS_ENABLE | USBH_PORTSTATUS_CONNECTION)) {
- goto reset_success;
- }
- }
-
- /* check for timeout */
- if (osalOsGetSystemTimeX() - start > HAL_USBH_PORT_RESET_TIMEOUT) break;
- }
- }
-
- /* reset procedure failed; abort */
- goto abort;
-
-reset_success:
-
- uinfo("Reset OK, recovery...");
-
- /* reset recovery */
- osalThreadSleepMilliseconds(100);
-
- /* initialize object */
- if (port->status & USBH_PORTSTATUS_LOW_SPEED) {
- speed = USBH_DEVSPEED_LOW;
- } else if (port->status & USBH_PORTSTATUS_HIGH_SPEED) {
- speed = USBH_DEVSPEED_HIGH;
- } else {
- speed = USBH_DEVSPEED_FULL;
- }
- _device_initialize(&port->device, speed);
- usbhEPOpen(&port->device.ctrl);
-
- /* device with default address (0), try enumeration */
- if (_device_enumerate(&port->device)) {
- /* enumeration failed */
- usbhEPClose(&port->device.ctrl);
-
- if (!--retries)
- goto abort;
-
- /* retry reset & enumeration */
- goto reset;
- }
-
- /* load the default language ID */
- uinfo("Loading langID0...");
- if (!usbhStdReqGetStringDescriptor(&port->device, 0, 0,
- USBH_DT_STRING_SIZE, (uint8_t *)&strdesc)
- && (strdesc.bLength >= 4)
- && !usbhStdReqGetStringDescriptor(&port->device, 0, 0,
- 4, (uint8_t *)&strdesc)) {
-
- port->device.langID0 = strdesc.wData[0];
- uinfof("langID0=%04x", port->device.langID0);
- }
-
- /* check if the device has only one configuration */
- if (port->device.devDesc.bNumConfigurations == 1) {
- uinfo("Device has only one configuration");
- _device_configure(&port->device, 0);
- }
-
- _classdriver_process_device(&port->device);
- return;
-
-abort:
- uerr("Abort");
- port->device.status = USBH_DEVSTATUS_DISCONNECTED;
-}
-
-void _usbh_port_disconnected(usbh_port_t *port) {
- if (port->device.status == USBH_DEVSTATUS_DISCONNECTED)
- return;
-
- uinfo("Port disconnected");
-
- /* unload drivers */
- while (port->device.drivers) {
- usbh_baseclassdriver_t *drv = port->device.drivers;
-
- /* unload */
- uinfof("Unload driver %s", drv->info->name);
- drv->info->vmt->unload(drv);
-
- /* unlink */
- drv->dev = 0;
- port->device.drivers = drv->next;
- }
-
- /* close control endpoint */
- osalSysLock();
- usbhEPCloseS(&port->device.ctrl);
- osalSysUnlock();
-
- /* free address */
- if (port->device.address)
- _free_address(port->device.host, port->device.address);
-
- _device_free_full_cfgdesc(&port->device);
-
- port->device.status = USBH_DEVSTATUS_DISCONNECTED;
-}
-
-
-
-/*===========================================================================*/
-/* Hub processing functions. */
-/*===========================================================================*/
-
-#if HAL_USBH_USE_HUB
-static void _hub_update_status(USBHDriver *host, USBHHubDriver *hub) {
- uint32_t stat;
- if (usbhhubControlRequest(host,
- hub,
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
- USBH_REQ_GET_STATUS,
- 0,
- 0,
- 4,
- (uint8_t *)&stat) != USBH_URBSTATUS_OK) {
- return;
- }
- if (hub) {
- hub->status = stat & 0xffff;
- hub->c_status |= stat >> 16;
- }
-}
-
-static void _hub_process_status_change(USBHDriver *host, USBHHubDriver *hub) {
- uinfo("Hub status change. GET_STATUS.");
- _hub_update_status(host, hub);
-
- if (hub->c_status & USBH_HUBSTATUS_C_HUB_LOCAL_POWER) {
- hub->c_status &= ~USBH_HUBSTATUS_C_HUB_LOCAL_POWER;
- uinfo("Clear USBH_HUB_FEAT_C_HUB_LOCAL_POWER");
- usbhhubClearFeatureHub(host, hub, USBH_HUB_FEAT_C_HUB_LOCAL_POWER);
- }
-
- if (hub->c_status & USBH_HUBSTATUS_C_HUB_OVER_CURRENT) {
- hub->c_status &= ~USBH_HUBSTATUS_C_HUB_OVER_CURRENT;
- uinfo("Clear USBH_HUB_FEAT_C_HUB_OVER_CURRENT");
- usbhhubClearFeatureHub(host, hub, USBH_HUB_FEAT_C_HUB_OVER_CURRENT);
- }
-}
-
-static uint32_t _hub_get_status_change_bitmap(USBHDriver *host, USBHHubDriver *hub) {
- if (hub != NULL) {
- osalSysLock();
- uint32_t ret = hub->statuschange;
- hub->statuschange = 0;
- osalOsRescheduleS();
- osalSysUnlock();
- return ret;
- }
- return usbh_lld_roothub_get_statuschange_bitmap(host);
-}
-
-#else
-//TODO: replace the functions above
-#endif
-
-#if HAL_USBH_USE_HUB
-static void _hub_process(USBHDriver *host, USBHHubDriver *hub) {
- uint32_t bitmap = _hub_get_status_change_bitmap(host, hub);
- if (!bitmap)
- return;
-
- if (bitmap & 1) {
- _hub_process_status_change(host, hub);
- bitmap &= ~1;
- }
-
- usbh_port_t *port = (hub == NULL) ? &host->rootport : hub->ports;
- uint8_t i;
- for (i = 1; i < 32; i++) {
- if (!bitmap || !port)
- break;
- if (bitmap & (1 << i)) {
- bitmap &= ~(1 << i);
- _port_process_status_change(port);
- }
- port = port->next;
- }
-
-}
-#else
-static void _hub_process(USBHDriver *host) {
- uint32_t bitmap = usbh_lld_roothub_get_statuschange_bitmap(host);
-
-#if 0 //TODO: complete _hub_process_status_change for root hub
- if (bitmap & 1) {
- _hub_process_status_change(host, hub);
- bitmap &= ~1;
- }
-#endif
-
- if (!bitmap)
- return;
-
- _port_process_status_change(&host->rootport);
-}
-#endif
-
-/*===========================================================================*/
-/* Main processing loop (enumeration, loading/unloading drivers, etc). */
-/*===========================================================================*/
-void usbhMainLoop(USBHDriver *usbh) {
-
- if (usbh->status == USBH_STATUS_STOPPED)
- return;
-
-#if HAL_USBH_USE_HUB
- /* process root hub */
- _hub_process(usbh, NULL);
-
- /* process connected hubs */
- USBHHubDriver *hub;
- list_for_each_entry(hub, USBHHubDriver, &usbh->hubs, node) {
- _hub_process(usbh, hub);
- }
-#else
- /* process root hub */
- _hub_process(usbh);
-#endif
-}
-
-
-/*===========================================================================*/
-/* IAD class driver. */
-/*===========================================================================*/
-#if HAL_USBH_USE_IAD
-static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
-static void iad_unload(usbh_baseclassdriver_t *drv);
-static const usbh_classdriver_vmt_t usbhiadClassDriverVMT = {
- iad_load,
- iad_unload
-};
-static const usbh_classdriverinfo_t usbhiadClassDriverInfo = {
- 0xef, 0x02, 0x01, "IAD", &usbhiadClassDriverVMT
-};
-
-static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev,
- const uint8_t *descriptor, uint16_t rem) {
- (void)rem;
-
- if (descriptor[1] != USBH_DT_DEVICE)
- return 0;
-
- uinfo("Load a driver for each IF collection.");
-
- generic_iterator_t icfg;
- if_iterator_t iif;
- const usbh_ia_descriptor_t *last_iad = 0;
-
- cfg_iter_init(&icfg, dev->fullConfigurationDescriptor,
- dev->basicConfigDesc.wTotalLength);
- if (!icfg.valid) {
- uerr("Invalid configuration descriptor.");
- return 0;
- }
-
- for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
- if (iif.iad && (iif.iad != last_iad)) {
- last_iad = iif.iad;
- if (_classdriver_load(dev, iif.iad->bFunctionClass,
- iif.iad->bFunctionSubClass,
- iif.iad->bFunctionProtocol,
- (uint8_t *)iif.iad,
- (uint8_t *)iif.curr - (uint8_t *)iif.iad + iif.rem) != HAL_SUCCESS) {
- uwarnf("No drivers found for IF collection #%d:%d",
- iif.iad->bFirstInterface,
- iif.iad->bFirstInterface + iif.iad->bInterfaceCount - 1);
- }
- }
- }
-
- return 0;
-}
-
-static void iad_unload(usbh_baseclassdriver_t *drv) {
- (void)drv;
-}
-#endif
-
-
-/*===========================================================================*/
-/* Class driver loader. */
-/*===========================================================================*/
-
-static const usbh_classdriverinfo_t *usbh_classdrivers_lookup[] = {
-#if HAL_USBH_USE_FTDI
- &usbhftdiClassDriverInfo,
-#endif
-#if HAL_USBH_USE_IAD
- &usbhiadClassDriverInfo,
-#endif
-#if HAL_USBH_USE_UVC
- &usbhuvcClassDriverInfo,
-#endif
-#if HAL_USBH_USE_MSD
- &usbhmsdClassDriverInfo,
-#endif
-#if HAL_USBH_USE_HUB
- &usbhhubClassDriverInfo
-#endif
-};
-
-static bool _classdriver_load(usbh_device_t *dev, uint8_t class,
- uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem) {
- uint8_t i;
- usbh_baseclassdriver_t *drv = NULL;
- for (i = 0; i < sizeof_array(usbh_classdrivers_lookup); i++) {
- const usbh_classdriverinfo_t *const info = usbh_classdrivers_lookup[i];
- if (class == 0xff) {
- /* vendor specific */
- if (info->class == 0xff) {
- uinfof("Try load vendor-specific driver %s", info->name);
- drv = info->vmt->load(dev, descbuff, rem);
- if (drv != NULL)
- goto success;
- }
- } else if ((info->class < 0) || ((info->class == class)
- && ((info->subclass < 0) || ((info->subclass == subclass)
- && ((info->protocol < 0) || (info->protocol == protocol)))))) {
- uinfof("Try load driver %s", info->name);
- drv = info->vmt->load(dev, descbuff, rem);
-
-#if HAL_USBH_USE_IAD
- /* special case: */
- if (info == &usbhiadClassDriverInfo)
- return HAL_SUCCESS;
-#endif
-
- if (drv != NULL)
- goto success;
- }
- }
- return HAL_FAILED;
-
-success:
- /* Link this driver to the device */
- drv->next = dev->drivers;
- dev->drivers = drv;
- drv->dev = dev;
- return HAL_SUCCESS;
-}
-
-static void _classdriver_process_device(usbh_device_t *dev) {
- uinfo("New device found.");
- const usbh_device_descriptor_t *const devdesc = &dev->devDesc;
-
- usbhDevicePrintInfo(dev);
-
- /* TODO: Support multiple configurations
- *
- * Windows doesn't support them, so it's unlikely that any commercial USB device
- * will have multiple configurations.
- */
- if (dev->status != USBH_DEVSTATUS_CONFIGURED) {
- uwarn("Multiple configurations not supported, selecting configuration #0");
- if (_device_configure(dev, 0) != HAL_SUCCESS) {
- uerr("Couldn't configure device; abort.");
- return;
- }
- }
-
- _device_read_full_cfgdesc(dev, dev->bConfiguration);
- if (dev->fullConfigurationDescriptor == NULL) {
- uerr("Couldn't read full configuration descriptor; abort.");
- return;
- }
-
- usbhDevicePrintConfiguration(dev->fullConfigurationDescriptor,
- dev->basicConfigDesc.wTotalLength);
-
- if (devdesc->bDeviceClass == 0) {
- /* each interface defines its own device class/subclass/protocol */
- uinfo("Load a driver for each IF.");
-
- generic_iterator_t icfg;
- if_iterator_t iif;
- uint8_t last_if = 0xff;
-
- cfg_iter_init(&icfg, dev->fullConfigurationDescriptor,
- dev->basicConfigDesc.wTotalLength);
- if (!icfg.valid) {
- uerr("Invalid configuration descriptor.");
- goto exit;
- }
-
- for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
- const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
- if (ifdesc->bInterfaceNumber != last_if) {
- last_if = ifdesc->bInterfaceNumber;
- if (_classdriver_load(dev, ifdesc->bInterfaceClass,
- ifdesc->bInterfaceSubClass,
- ifdesc->bInterfaceProtocol,
- (uint8_t *)ifdesc, iif.rem) != HAL_SUCCESS) {
- uwarnf("No drivers found for IF #%d", ifdesc->bInterfaceNumber);
- }
- }
- }
-
- } else {
- if (_classdriver_load(dev, devdesc->bDeviceClass,
- devdesc->bDeviceSubClass,
- devdesc->bDeviceProtocol,
- (uint8_t *)devdesc, USBH_DT_DEVICE_SIZE) != HAL_SUCCESS) {
- uwarn("No drivers found.");
- }
- }
-
-exit:
- if (dev->keepFullCfgDesc == 0) {
- _device_free_full_cfgdesc(dev);
- }
-}
-
-
-#endif
-
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +#if HAL_USE_USBH + +#include "usbh/dev/hub.h" +#include "usbh/internal.h" +#include <string.h> + +#if USBH_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBH_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBH_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBH_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + +#if STM32_USBH_USE_OTG1 +USBHDriver USBHD1; +#endif +#if STM32_USBH_USE_OTG2 +USBHDriver USBHD2; +#endif + + +static void _classdriver_process_device(usbh_device_t *dev); +static bool _classdriver_load(usbh_device_t *dev, uint8_t class, + uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem); + + +/*===========================================================================*/ +/* Checks. */ +/*===========================================================================*/ + +static inline void _check_dev(usbh_device_t *dev) { + osalDbgCheck(dev); + //TODO: add more checks. +} + +static inline void _check_ep(usbh_ep_t *ep) { + osalDbgCheck(ep != 0); + _check_dev(ep->device); + osalDbgCheck(ep->type <= 3); + //TODO: add more checks. +} + +static inline void _check_urb(usbh_urb_t *urb) { + osalDbgCheck(urb != 0); + _check_ep(urb->ep); + osalDbgCheck((urb->buff != NULL) || (urb->requestedLength == 0)); + //TODO: add more checks. +} + +/*===========================================================================*/ +/* Main driver API. */ +/*===========================================================================*/ + +void usbhObjectInit(USBHDriver *usbh) { + memset(usbh, 0, sizeof(*usbh)); + usbh->status = USBH_STATUS_STOPPED; +#if HAL_USBH_USE_HUB + INIT_LIST_HEAD(&usbh->hubs); + _usbhub_port_object_init(&usbh->rootport, usbh, 0, 1); +#else + _usbhub_port_object_init(&usbh->rootport, usbh, 1); +#endif +} + +void usbhInit(void) { +#if HAL_USBH_USE_HUB + uint8_t i; + for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) { + usbhhubObjectInit(&USBHHUBD[i]); + } +#endif + usbh_lld_init(); +} + +void usbhStart(USBHDriver *usbh) { + usbDbgInit(usbh); + + osalSysLock(); + osalDbgAssert((usbh->status == USBH_STATUS_STOPPED) || (usbh->status == USBH_STATUS_STARTED), + "invalid state"); + usbh_lld_start(usbh); + usbh->status = USBH_STATUS_STARTED; + osalOsRescheduleS(); + osalSysUnlock(); +} + + +void usbhStop(USBHDriver *usbh) { + //TODO: implement + (void)usbh; +} +void usbhSuspend(USBHDriver *usbh) { + //TODO: implement + (void)usbh; +} +void usbhResume(USBHDriver *usbh) { + //TODO: implement + (void)usbh; +} + +/*===========================================================================*/ +/* Endpoint API. */ +/*===========================================================================*/ + +void usbhEPObjectInit(usbh_ep_t *ep, usbh_device_t *dev, const usbh_endpoint_descriptor_t *desc) { + osalDbgCheck(ep); + _check_dev(dev); + osalDbgCheck(desc); + + memset(ep, 0, sizeof(*ep)); + ep->device = dev; + ep->wMaxPacketSize = desc->wMaxPacketSize; + ep->address = desc->bEndpointAddress & 0x0F; + ep->type = (usbh_eptype_t) (desc->bmAttributes & 0x03); + if (ep->type != USBH_EPTYPE_CTRL) { + ep->in = (desc->bEndpointAddress & 0x80) ? TRUE : FALSE; + } + ep->bInterval = desc->bInterval; + + /* low-level part */ + usbh_lld_ep_object_init(ep); + + ep->status = USBH_EPSTATUS_CLOSED; +} + + +static void _ep0_object_init(usbh_device_t *dev, uint16_t wMaxPacketSize) { + const usbh_endpoint_descriptor_t ep0_descriptor = { + 7, //bLength + 5, //bDescriptorType + 0, //bEndpointAddress + 0, //bmAttributes + wMaxPacketSize, + 0, //bInterval + }; + usbhEPObjectInit(&dev->ctrl, dev, &ep0_descriptor); + usbhEPSetName(&dev->ctrl, "DEV[CTRL]"); +} + + +/*===========================================================================*/ +/* URB API. */ +/*===========================================================================*/ + +void usbhURBObjectInit(usbh_urb_t *urb, usbh_ep_t *ep, usbh_completion_cb callback, + void *user, void *buff, uint32_t len) { + + osalDbgCheck(urb != 0); + _check_ep(ep); + + /* initialize the common part: */ + urb->ep = ep; + urb->callback = callback; + urb->userData = user; + urb->buff = buff; + urb->requestedLength = len; + urb->actualLength = 0; + urb->status = USBH_URBSTATUS_INITIALIZED; + urb->waitingThread = 0; + urb->abortingThread = 0; + + /* initialize the ll part: */ + usbh_lld_urb_object_init(urb); +} + +void usbhURBObjectResetI(usbh_urb_t *urb) { + osalDbgAssert(!usbhURBIsBusy(urb), "invalid status"); + + osalDbgCheck((urb->waitingThread == 0) && (urb->abortingThread == 0)); + + urb->actualLength = 0; + urb->status = USBH_URBSTATUS_INITIALIZED; + + /* reset the ll part: */ + usbh_lld_urb_object_reset(urb); +} + +void usbhURBSubmitI(usbh_urb_t *urb) { + osalDbgCheckClassI(); + _check_urb(urb); + osalDbgAssert(urb->status == USBH_URBSTATUS_INITIALIZED, "invalid status"); + usbh_ep_t *const ep = urb->ep; + if (ep->status == USBH_EPSTATUS_HALTED) { + _usbh_urb_completeI(urb, USBH_URBSTATUS_STALL); + return; + } + if (ep->status != USBH_EPSTATUS_OPEN) { + _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED); + return; + } + if (!(usbhDeviceGetPort(ep->device)->status & USBH_PORTSTATUS_ENABLE)) { + _usbh_urb_completeI(urb, USBH_URBSTATUS_DISCONNECTED); + return; + } + urb->status = USBH_URBSTATUS_PENDING; + usbh_lld_urb_submit(urb); +} + +bool _usbh_urb_abortI(usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheckClassI(); + _check_urb(urb); + + switch (urb->status) { +/* case USBH_URBSTATUS_UNINITIALIZED: + * case USBH_URBSTATUS_INITIALIZED: + * case USBH_URBSTATUS_ERROR: + * case USBH_URBSTATUS_TIMEOUT: + * case USBH_URBSTATUS_CANCELLED: + * case USBH_URBSTATUS_STALL: + * case USBH_URBSTATUS_DISCONNECTED: + * case USBH_URBSTATUS_OK: */ + default: + /* already finished */ + _usbh_urb_completeI(urb, status); + return TRUE; + +// case USBH_URBSTATUS_QUEUED: + case USBH_URBSTATUS_PENDING: + return usbh_lld_urb_abort(urb, status); + } +} + +void _usbh_urb_abort_and_waitS(usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheckClassS(); + _check_urb(urb); + + if (_usbh_urb_abortI(urb, status) == FALSE) { + uwarn("URB wasn't aborted immediately, suspend"); + osalThreadSuspendS(&urb->abortingThread); + urb->abortingThread = 0; + } else { + osalOsRescheduleS(); + } + uwarn("URB aborted"); +} + +bool usbhURBCancelI(usbh_urb_t *urb) { + return _usbh_urb_abortI(urb, USBH_URBSTATUS_CANCELLED); +} + +void usbhURBCancelAndWaitS(usbh_urb_t *urb) { + _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_CANCELLED); +} + +msg_t usbhURBWaitTimeoutS(usbh_urb_t *urb, systime_t timeout) { + msg_t ret; + + osalDbgCheckClassS(); + _check_urb(urb); + + switch (urb->status) { + case USBH_URBSTATUS_INITIALIZED: + case USBH_URBSTATUS_PENDING: +// case USBH_URBSTATUS_QUEUED: + ret = osalThreadSuspendTimeoutS(&urb->waitingThread, timeout); + urb->waitingThread = 0; + break; + + case USBH_URBSTATUS_OK: + ret = MSG_OK; + osalOsRescheduleS(); + break; + +/* case USBH_URBSTATUS_UNINITIALIZED: + * case USBH_URBSTATUS_ERROR: + * case USBH_URBSTATUS_TIMEOUT: + * case USBH_URBSTATUS_CANCELLED: + * case USBH_URBSTATUS_STALL: + * case USBH_URBSTATUS_DISCONNECTED: */ + default: + ret = MSG_RESET; + osalOsRescheduleS(); + break; + } + return ret; +} + +msg_t usbhURBSubmitAndWaitS(usbh_urb_t *urb, systime_t timeout) { + msg_t ret; + + osalDbgCheckClassS(); + _check_urb(urb); + + usbhURBSubmitI(urb); + ret = usbhURBWaitTimeoutS(urb, timeout); + if (ret == MSG_TIMEOUT) + _usbh_urb_abort_and_waitS(urb, USBH_URBSTATUS_TIMEOUT); + + return ret; +} + +static inline msg_t _wakeup_message(usbh_urbstatus_t status) { + if (status == USBH_URBSTATUS_OK) return MSG_OK; + if (status == USBH_URBSTATUS_TIMEOUT) return MSG_TIMEOUT; + return MSG_RESET; +} + +void _usbh_urb_completeI(usbh_urb_t *urb, usbh_urbstatus_t status) { + osalDbgCheckClassI(); + _check_urb(urb); + urb->status = status; + osalThreadResumeI(&urb->waitingThread, _wakeup_message(status)); + osalThreadResumeI(&urb->abortingThread, MSG_RESET); + if (urb->callback) + urb->callback(urb); +} + +/*===========================================================================*/ +/* Synchronous API. */ +/*===========================================================================*/ + +usbh_urbstatus_t usbhBulkTransfer(usbh_ep_t *ep, + void *data, + uint32_t len, + uint32_t *actual_len, + systime_t timeout) { + + osalDbgCheck(ep != NULL); + osalDbgCheck((data != NULL) || (len == 0)); + osalDbgAssert(ep->type == USBH_EPTYPE_BULK, "wrong ep"); + + usbh_urb_t urb; + usbhURBObjectInit(&urb, ep, 0, 0, data, len); + + osalSysLock(); + usbhURBSubmitAndWaitS(&urb, timeout); + osalSysUnlock(); + + if (actual_len != NULL) + *actual_len = urb.actualLength; + + return urb.status; +} + +usbh_urbstatus_t usbhControlRequestExtended(usbh_device_t *dev, + const usbh_control_request_t *req, + uint8_t *buff, + uint32_t *actual_len, + systime_t timeout) { + + _check_dev(dev); + osalDbgCheck(req != NULL); + + usbh_urb_t urb; + + usbhURBObjectInit(&urb, &dev->ctrl, 0, 0, buff, req->wLength); + urb.setup_buff = req; + + osalSysLock(); + usbhURBSubmitAndWaitS(&urb, timeout); + osalSysUnlock(); + + if (actual_len != NULL) + *actual_len = urb.actualLength; + + return urb.status; +} + +usbh_urbstatus_t usbhControlRequest(usbh_device_t *dev, + uint8_t bmRequestType, + uint8_t bRequest, + uint16_t wValue, + uint16_t wIndex, + uint16_t wLength, + uint8_t *buff) { + + const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = { + bmRequestType, + bRequest, + wValue, + wIndex, + wLength + }; + return usbhControlRequestExtended(dev, &req, buff, NULL, MS2ST(1000)); +} + +/*===========================================================================*/ +/* Standard request helpers. */ +/*===========================================================================*/ + +#define USBH_GET_DESCRIPTOR(type, value, index) \ + USBH_STANDARDIN(type, \ + USBH_REQ_GET_DESCRIPTOR, \ + value, \ + index) \ + +#define USBH_GETDEVICEDESCRIPTOR \ + USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_DEVICE << 8) | 0, 0) + +#define USBH_GETCONFIGURATIONDESCRIPTOR(index) \ + USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_CONFIG << 8) | index, 0) + +#define USBH_GETSTRINGDESCRIPTOR(index, langID) \ + USBH_GET_DESCRIPTOR(USBH_REQTYPE_DEVICE, (USBH_DT_STRING << 8) | index, langID) + +bool usbhStdReqGetDeviceDescriptor(usbh_device_t *dev, + uint16_t wLength, + uint8_t *buf) { + usbh_device_descriptor_t *desc; + usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETDEVICEDESCRIPTOR, wLength, buf); + desc = (usbh_device_descriptor_t *)buf; + if ((ret != USBH_URBSTATUS_OK) + || (desc->bLength != USBH_DT_DEVICE_SIZE) + || (desc->bDescriptorType != USBH_DT_DEVICE)) { + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +bool usbhStdReqGetConfigurationDescriptor(usbh_device_t *dev, + uint8_t index, + uint16_t wLength, + uint8_t *buf) { + usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETCONFIGURATIONDESCRIPTOR(index), wLength, buf); + usbh_config_descriptor_t *const desc = (usbh_config_descriptor_t *)buf; + if ((ret != USBH_URBSTATUS_OK) + || (desc->bLength < USBH_DT_CONFIG_SIZE) + || (desc->bDescriptorType != USBH_DT_CONFIG)) { + return HAL_FAILED; + } + return HAL_SUCCESS; +} + +bool usbhStdReqGetStringDescriptor(usbh_device_t *dev, + uint8_t index, + uint16_t langID, + uint16_t wLength, + uint8_t *buf) { + + osalDbgAssert(wLength >= USBH_DT_STRING_SIZE, "wrong size"); + usbh_string_descriptor_t *desc = (usbh_string_descriptor_t *)buf; + usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GETSTRINGDESCRIPTOR(index, langID), wLength, buf); + if ((ret != USBH_URBSTATUS_OK) + || (desc->bLength < USBH_DT_STRING_SIZE) + || (desc->bDescriptorType != USBH_DT_STRING)) { + return HAL_FAILED; + } + return HAL_SUCCESS; +} + + + +#define USBH_SET_INTERFACE(interface, alt) \ + USBH_STANDARDOUT(USBH_REQTYPE_INTERFACE, \ + USBH_REQ_SET_INTERFACE, \ + alt, \ + interface) \ + +#define USBH_GET_INTERFACE(interface) \ + USBH_STANDARDIN(USBH_REQTYPE_INTERFACE, \ + USBH_REQ_GET_INTERFACE, \ + 0, \ + interface) \ + +bool usbhStdReqSetInterface(usbh_device_t *dev, + uint8_t bInterfaceNumber, + uint8_t bAlternateSetting) { + + usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_SET_INTERFACE(bInterfaceNumber, bAlternateSetting), 0, NULL); + if (ret != USBH_URBSTATUS_OK) + return HAL_FAILED; + + return HAL_SUCCESS; +} + +bool usbhStdReqGetInterface(usbh_device_t *dev, + uint8_t bInterfaceNumber, + uint8_t *bAlternateSetting) { + + USBH_DEFINE_BUFFER(uint8_t, alt); + + usbh_urbstatus_t ret = usbhControlRequest(dev, USBH_GET_INTERFACE(bInterfaceNumber), 1, &alt); + if (ret != USBH_URBSTATUS_OK) + return HAL_FAILED; + + *bAlternateSetting = alt; + return HAL_SUCCESS; +} + + +/*===========================================================================*/ +/* Device-related functions. */ +/*===========================================================================*/ + +static uint8_t _find_address(USBHDriver *host) { + uint8_t addr, i, j; + for (i = 0; i < sizeof_array(host->address_bitmap); i++) { + addr = host->address_bitmap[i]; + for (j = 0; j < 8; j++) { + if ((addr & (1 << j)) == 0) { + //found: + addr = i * 8 + j + 1; + host->address_bitmap[i] |= (1 << j); + return addr; + } + } + } + return 0; +} + +static void _free_address(USBHDriver *host, uint8_t addr) { + uinfof("Free address %d", addr); + host->address_bitmap[addr / 8] &= ~(1 << ((addr - 1) & 7)); +} + +static void _device_initialize(usbh_device_t *dev, usbh_devspeed_t speed) { + dev->address = 0; + dev->speed = speed; + dev->status = USBH_DEVSTATUS_DEFAULT; + dev->langID0 = 0; + dev->keepFullCfgDesc = 0; + _ep0_object_init(dev, 64); +} + +static bool _device_setaddress(usbh_device_t *dev, uint8_t address) { + usbh_urbstatus_t ret = usbhControlRequest(dev, + USBH_STANDARDOUT(USBH_REQTYPE_DEVICE, USBH_REQ_SET_ADDRESS, address, 0), + 0, + 0); + if (ret != USBH_URBSTATUS_OK) + return HAL_FAILED; + + dev->address = address; + return HAL_SUCCESS; +} + +static inline bool _device_read_basic_cfgdesc(usbh_device_t *dev, uint8_t bConfiguration) { + /* get configuration descriptor */ + return usbhStdReqGetConfigurationDescriptor(dev, bConfiguration, + sizeof(dev->basicConfigDesc), (uint8_t *)&dev->basicConfigDesc); +} + +static void _device_read_full_cfgdesc(usbh_device_t *dev, uint8_t bConfiguration) { + _check_dev(dev); + + uint8_t i; + + if (dev->fullConfigurationDescriptor != NULL) { + chHeapFree(dev->fullConfigurationDescriptor); + } + + dev->fullConfigurationDescriptor = + (uint8_t *)chHeapAlloc(0, dev->basicConfigDesc.wTotalLength); + + if (!dev->fullConfigurationDescriptor) + return; + + for (i = 0; i < 3; i++) { + if (usbhStdReqGetConfigurationDescriptor(dev, bConfiguration, + dev->basicConfigDesc.wTotalLength, + dev->fullConfigurationDescriptor) == HAL_SUCCESS) { + return; + } + osalThreadSleepMilliseconds(200); + } + + /* error */ + chHeapFree(dev->fullConfigurationDescriptor); + dev->fullConfigurationDescriptor = NULL; +} + +static void _device_free_full_cfgdesc(usbh_device_t *dev) { + osalDbgCheck(dev); + if (dev->fullConfigurationDescriptor != NULL) { + chHeapFree(dev->fullConfigurationDescriptor); + dev->fullConfigurationDescriptor = NULL; + } +} + + +#define USBH_SET_CONFIGURATION(type, value, index) \ + USBH_STANDARDOUT(type, \ + USBH_REQ_SET_CONFIGURATION, \ + value, \ + index) \ + +#define USBH_SETDEVICECONFIGURATION(index) \ + USBH_SET_CONFIGURATION(USBH_REQTYPE_DEVICE, index, 0) + + +static bool _device_set_configuration(usbh_device_t *dev, uint8_t configuration) { + usbh_urbstatus_t ret = usbhControlRequest(dev, + USBH_SETDEVICECONFIGURATION(configuration), + 0, + 0); + if (ret != USBH_URBSTATUS_OK) + return HAL_FAILED; + return HAL_SUCCESS; +} + +static bool _device_configure(usbh_device_t *dev, uint8_t bConfiguration) { + uint8_t i; + + uinfof("Reading basic configuration descriptor %d", bConfiguration); + for (i = 0; i < 3; i++) { + if (!_device_read_basic_cfgdesc(dev, bConfiguration)) + break; + } + + if (i == 3) { + uerrf("Could not read basic configuration descriptor %d; " + "won't configure device", bConfiguration); + return HAL_FAILED; + } + + uinfof("Selecting configuration %d", bConfiguration); + for (i = 0; i < 3; i++) { + if (!_device_set_configuration(dev, dev->basicConfigDesc.bConfigurationValue)) { + /* TODO: check if correctly configured using GET_CONFIGURATION */ + dev->status = USBH_DEVSTATUS_CONFIGURED; + dev->bConfiguration = bConfiguration; + + uinfo("Device configured."); + return HAL_SUCCESS; + } + } + + return HAL_FAILED; +} + +static bool _device_enumerate(usbh_device_t *dev) { + + uinfo("Enumerate."); + uinfo("Get first 8 bytes of device descriptor"); + + /* get first 8 bytes of device descriptor */ + if (usbhStdReqGetDeviceDescriptor(dev, 8, (uint8_t *)&dev->devDesc)) { + uerr("Error"); + return HAL_FAILED; + } + + uinfof("Configure bMaxPacketSize0 = %d", dev->devDesc.bMaxPacketSize0); + /* configure EP0 wMaxPacketSize */ + usbhEPClose(&dev->ctrl); + _ep0_object_init(dev, dev->devDesc.bMaxPacketSize0); + usbhEPOpen(&dev->ctrl); + + uint8_t addr = _find_address(dev->host); + if (addr == 0) { + uerr("No free addresses found"); + return HAL_FAILED; + } + + /* set device address */ + uinfof("Set device address: %d", addr); + if (_device_setaddress(dev, addr)) { + uerr("Error"); + _free_address(dev->host, addr); + return HAL_FAILED; + } + + /* update EP because of the address change */ + usbhEPClose(&dev->ctrl); + _ep0_object_init(dev, dev->devDesc.bMaxPacketSize0); + usbhEPOpen(&dev->ctrl); + + uinfof("Wait stabilization..."); + osalThreadSleepMilliseconds(HAL_USBH_DEVICE_ADDRESS_STABILIZATION); + + /* address is set */ + dev->status = USBH_DEVSTATUS_ADDRESS; + + uinfof("Get full device desc"); + /* get full device descriptor */ + if (usbhStdReqGetDeviceDescriptor(dev, sizeof(dev->devDesc), + (uint8_t *)&dev->devDesc)) { + uerr("Error"); + _device_setaddress(dev, 0); + _free_address(dev->host, addr); + return HAL_FAILED; + } + + uinfof("Enumeration finished."); + return HAL_SUCCESS; +} + +#if USBH_DEBUG_ENABLE && USBH_DEBUG_ENABLE_INFO +void usbhDevicePrintInfo(usbh_device_t *dev) { + USBH_DEFINE_BUFFER(char, str[64]); + usbh_device_descriptor_t *const desc = &dev->devDesc; + + uinfo("----- Device info -----"); + uinfo("Device descriptor:"); + uinfof("\tUSBSpec=%04x, #configurations=%d, langID0=%04x", + desc->bcdUSB, + desc->bNumConfigurations, + dev->langID0); + + uinfof("\tClass=%02x, Subclass=%02x, Protocol=%02x", + desc->bDeviceClass, + desc->bDeviceSubClass, + desc->bDeviceProtocol); + + uinfof("\tVID=%04x, PID=%04x, Release=%04x", + desc->idVendor, + desc->idProduct, + desc->bcdDevice); + + if (dev->langID0) { + usbhDeviceReadString(dev, str, sizeof(str), desc->iManufacturer, dev->langID0); + uinfof("\tManufacturer: %s", str); + usbhDeviceReadString(dev, str, sizeof(str), desc->iProduct, dev->langID0); + uinfof("\tProduct: %s", str); + usbhDeviceReadString(dev, str, sizeof(str), desc->iSerialNumber, dev->langID0); + uinfof("\tSerial Number: %s", str); + } + + if (dev->status == USBH_DEVSTATUS_CONFIGURED) { + uinfo("Configuration descriptor (partial):"); + usbh_config_descriptor_t *const cfg = &dev->basicConfigDesc; + uinfof("\tbConfigurationValue=%d, Length=%d, #interfaces=%d", + cfg->bConfigurationValue, + cfg->wTotalLength, + cfg->bNumInterfaces); + + uinfof("\tCurrent=%dmA", cfg->bMaxPower * 2); + uinfof("\tSelfPowered=%d, RemoteWakeup=%d", + cfg->bmAttributes & 0x40 ? 1 : 0, + cfg->bmAttributes & 0x20 ? 1 : 0); + if (dev->langID0) { + usbhDeviceReadString(dev, str, sizeof(str), cfg->iConfiguration, dev->langID0); + uinfof("\tName: %s", str); + } + } + + uinfo("----- End Device info -----"); + +} + +void usbhDevicePrintConfiguration(const uint8_t *descriptor, uint16_t rem) { + generic_iterator_t iep, icfg, ics; + if_iterator_t iif; + + uinfo("----- Configuration info -----"); + uinfo("Configuration descriptor:"); + cfg_iter_init(&icfg, descriptor, rem); + const usbh_config_descriptor_t *const cfgdesc = cfg_get(&icfg); + uinfof("Configuration %d, #IFs=%d", cfgdesc->bConfigurationValue, cfgdesc->bNumInterfaces); + + for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { + const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); + + uinfof(" Interface %d, alt=%d, #EPs=%d, " + "Class=%02x, Subclass=%02x, Protocol=%02x", + ifdesc->bInterfaceNumber, ifdesc->bAlternateSetting, ifdesc->bNumEndpoints, + ifdesc->bInterfaceClass, ifdesc->bInterfaceSubClass, ifdesc->bInterfaceProtocol); + + for (cs_iter_init(&ics, (generic_iterator_t *)&iif); ics.valid; cs_iter_next(&ics)) { + uinfof(" Class-Specific descriptor, Length=%d, Type=%02x", + ics.curr[0], ics.curr[1]); + } + + for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) { + const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep); + + uinfof(" Endpoint descriptor, Address=%02x, Type=%d, MaxPacket=%d, Interval=%d", + epdesc->bEndpointAddress, + epdesc->bmAttributes & 3, + epdesc->wMaxPacketSize, + epdesc->bInterval); + + for (cs_iter_init(&ics, &iep); ics.valid; cs_iter_next(&ics)) { + uinfof(" Class-Specific descriptor, Length=%d, Type=%02x", + ics.curr[0], ics.curr[1]); + } + } + } + uinfo("----- End Configuration info -----"); +} +#endif + +bool usbhDeviceReadString(usbh_device_t *dev, char *dest, uint8_t size, + uint8_t index, uint16_t langID) { + + usbh_string_descriptor_t *const desc = (usbh_string_descriptor_t *)dest; + osalDbgAssert(size >= 2, "wrong size"); + + *dest = 0; + if (index == 0) + return HAL_SUCCESS; + if (usbhStdReqGetStringDescriptor(dev, index, langID, size, (uint8_t *)dest)) + return HAL_FAILED; + if (desc->bLength & 1) + return HAL_FAILED; + if (desc->bLength <= 2) + return HAL_SUCCESS; + + uint8_t nchars = desc->bLength / 2; /* including the trailing 0 */ + if (size < nchars) + nchars = size; + + char *src = (char *)&desc->wData[0]; + while (--nchars) { + *dest++ = *src; + src += 2; + } + *dest = 0; + return HAL_SUCCESS; +} + + + + +/*===========================================================================*/ +/* Port processing functions. */ +/*===========================================================================*/ + +static void _port_connected(usbh_port_t *port); + +static void _port_reset(usbh_port_t *port) { + usbhhubControlRequest(port->device.host, +#if HAL_USBH_USE_HUB + port->hub, +#endif + USBH_REQTYPE_OUT | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER, + USBH_REQ_SET_FEATURE, + USBH_PORT_FEAT_RESET, + port->number, + 0, + 0); +} + +static void _port_update_status(usbh_port_t *port) { + uint32_t stat; + if (usbhhubControlRequest(port->device.host, +#if HAL_USBH_USE_HUB + port->hub, +#endif + USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_OTHER, + USBH_REQ_GET_STATUS, + 0, + port->number, + 4, + (uint8_t *)&stat) != USBH_URBSTATUS_OK) { + return; + } + port->status = stat & 0xffff; + port->c_status |= stat >> 16; +} + +static void _port_process_status_change(usbh_port_t *port) { + + _port_update_status(port); + + if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) { + /* port connected status changed */ + port->c_status &= ~USBH_PORTSTATUS_C_CONNECTION; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_CONNECTION); + if ((port->status & (USBH_PORTSTATUS_CONNECTION | USBH_PORTSTATUS_ENABLE)) + == USBH_PORTSTATUS_CONNECTION) { + if (port->device.status != USBH_DEVSTATUS_DISCONNECTED) { + _usbh_port_disconnected(port); + } + + /* connected, disabled */ + _port_connected(port); + } else { + /* disconnected */ + _usbh_port_disconnected(port); + } + } + + if (port->c_status & USBH_PORTSTATUS_C_RESET) { + port->c_status &= ~USBH_PORTSTATUS_C_RESET; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_RESET); + } + + if (port->c_status & USBH_PORTSTATUS_C_ENABLE) { + port->c_status &= ~USBH_PORTSTATUS_C_ENABLE; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_ENABLE); + } + + if (port->c_status & USBH_PORTSTATUS_C_OVERCURRENT) { + port->c_status &= ~USBH_PORTSTATUS_C_OVERCURRENT; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_OVERCURRENT); + } + + if (port->c_status & USBH_PORTSTATUS_C_SUSPEND) { + port->c_status &= ~USBH_PORTSTATUS_C_SUSPEND; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_SUSPEND); + } + +} + + +static void _port_connected(usbh_port_t *port) { + /* connected */ + + systime_t start; + uint8_t i; + uint8_t retries; + usbh_devspeed_t speed; + USBH_DEFINE_BUFFER(usbh_string_descriptor_t, strdesc); + + uinfof("Port %d connected, wait debounce...", port->number); + + port->device.status = USBH_DEVSTATUS_ATTACHED; + + /* wait for attach de-bounce */ + osalThreadSleepMilliseconds(HAL_USBH_PORT_DEBOUNCE_TIME); + + /* check disconnection */ + _port_update_status(port); + if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) { + /* connection state changed; abort */ + goto abort; + } + + port->device.status = USBH_DEVSTATUS_CONNECTED; + retries = 3; + +reset: + for (i = 0; i < 3; i++) { + uinfo("Try reset..."); + port->c_status &= ~(USBH_PORTSTATUS_C_RESET | USBH_PORTSTATUS_C_ENABLE); + _port_reset(port); + osalThreadSleepMilliseconds(20); /* give it some time to reset (min. 10ms) */ + start = osalOsGetSystemTimeX(); + while (TRUE) { + _port_update_status(port); + + /* check for disconnection */ + if (port->c_status & USBH_PORTSTATUS_C_CONNECTION) + goto abort; + + /* check for reset completion */ + if (port->c_status & USBH_PORTSTATUS_C_RESET) { + port->c_status &= ~USBH_PORTSTATUS_C_RESET; + usbhhubClearFeaturePort(port, USBH_PORT_FEAT_C_RESET); + + if ((port->status & (USBH_PORTSTATUS_ENABLE | USBH_PORTSTATUS_CONNECTION)) + == (USBH_PORTSTATUS_ENABLE | USBH_PORTSTATUS_CONNECTION)) { + goto reset_success; + } + } + + /* check for timeout */ + if (osalOsGetSystemTimeX() - start > HAL_USBH_PORT_RESET_TIMEOUT) break; + } + } + + /* reset procedure failed; abort */ + goto abort; + +reset_success: + + uinfo("Reset OK, recovery..."); + + /* reset recovery */ + osalThreadSleepMilliseconds(100); + + /* initialize object */ + if (port->status & USBH_PORTSTATUS_LOW_SPEED) { + speed = USBH_DEVSPEED_LOW; + } else if (port->status & USBH_PORTSTATUS_HIGH_SPEED) { + speed = USBH_DEVSPEED_HIGH; + } else { + speed = USBH_DEVSPEED_FULL; + } + _device_initialize(&port->device, speed); + usbhEPOpen(&port->device.ctrl); + + /* device with default address (0), try enumeration */ + if (_device_enumerate(&port->device)) { + /* enumeration failed */ + usbhEPClose(&port->device.ctrl); + + if (!--retries) + goto abort; + + /* retry reset & enumeration */ + goto reset; + } + + /* load the default language ID */ + uinfo("Loading langID0..."); + if (!usbhStdReqGetStringDescriptor(&port->device, 0, 0, + USBH_DT_STRING_SIZE, (uint8_t *)&strdesc) + && (strdesc.bLength >= 4) + && !usbhStdReqGetStringDescriptor(&port->device, 0, 0, + 4, (uint8_t *)&strdesc)) { + + port->device.langID0 = strdesc.wData[0]; + uinfof("langID0=%04x", port->device.langID0); + } + + /* check if the device has only one configuration */ + if (port->device.devDesc.bNumConfigurations == 1) { + uinfo("Device has only one configuration"); + _device_configure(&port->device, 0); + } + + _classdriver_process_device(&port->device); + return; + +abort: + uerr("Abort"); + port->device.status = USBH_DEVSTATUS_DISCONNECTED; +} + +void _usbh_port_disconnected(usbh_port_t *port) { + if (port->device.status == USBH_DEVSTATUS_DISCONNECTED) + return; + + uinfo("Port disconnected"); + + /* unload drivers */ + while (port->device.drivers) { + usbh_baseclassdriver_t *drv = port->device.drivers; + + /* unload */ + uinfof("Unload driver %s", drv->info->name); + drv->info->vmt->unload(drv); + + /* unlink */ + drv->dev = 0; + port->device.drivers = drv->next; + } + + /* close control endpoint */ + osalSysLock(); + usbhEPCloseS(&port->device.ctrl); + osalSysUnlock(); + + /* free address */ + if (port->device.address) + _free_address(port->device.host, port->device.address); + + _device_free_full_cfgdesc(&port->device); + + port->device.status = USBH_DEVSTATUS_DISCONNECTED; +} + + + +/*===========================================================================*/ +/* Hub processing functions. */ +/*===========================================================================*/ + +#if HAL_USBH_USE_HUB +static void _hub_update_status(USBHDriver *host, USBHHubDriver *hub) { + uint32_t stat; + if (usbhhubControlRequest(host, + hub, + USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE, + USBH_REQ_GET_STATUS, + 0, + 0, + 4, + (uint8_t *)&stat) != USBH_URBSTATUS_OK) { + return; + } + if (hub) { + hub->status = stat & 0xffff; + hub->c_status |= stat >> 16; + } +} + +static void _hub_process_status_change(USBHDriver *host, USBHHubDriver *hub) { + uinfo("Hub status change. GET_STATUS."); + _hub_update_status(host, hub); + + if (hub->c_status & USBH_HUBSTATUS_C_HUB_LOCAL_POWER) { + hub->c_status &= ~USBH_HUBSTATUS_C_HUB_LOCAL_POWER; + uinfo("Clear USBH_HUB_FEAT_C_HUB_LOCAL_POWER"); + usbhhubClearFeatureHub(host, hub, USBH_HUB_FEAT_C_HUB_LOCAL_POWER); + } + + if (hub->c_status & USBH_HUBSTATUS_C_HUB_OVER_CURRENT) { + hub->c_status &= ~USBH_HUBSTATUS_C_HUB_OVER_CURRENT; + uinfo("Clear USBH_HUB_FEAT_C_HUB_OVER_CURRENT"); + usbhhubClearFeatureHub(host, hub, USBH_HUB_FEAT_C_HUB_OVER_CURRENT); + } +} + +static uint32_t _hub_get_status_change_bitmap(USBHDriver *host, USBHHubDriver *hub) { + if (hub != NULL) { + osalSysLock(); + uint32_t ret = hub->statuschange; + hub->statuschange = 0; + osalOsRescheduleS(); + osalSysUnlock(); + return ret; + } + return usbh_lld_roothub_get_statuschange_bitmap(host); +} + +#else +//TODO: replace the functions above +#endif + +#if HAL_USBH_USE_HUB +static void _hub_process(USBHDriver *host, USBHHubDriver *hub) { + uint32_t bitmap = _hub_get_status_change_bitmap(host, hub); + if (!bitmap) + return; + + if (bitmap & 1) { + _hub_process_status_change(host, hub); + bitmap &= ~1; + } + + usbh_port_t *port = (hub == NULL) ? &host->rootport : hub->ports; + uint8_t i; + for (i = 1; i < 32; i++) { + if (!bitmap || !port) + break; + if (bitmap & (1 << i)) { + bitmap &= ~(1 << i); + _port_process_status_change(port); + } + port = port->next; + } + +} +#else +static void _hub_process(USBHDriver *host) { + uint32_t bitmap = usbh_lld_roothub_get_statuschange_bitmap(host); + +#if 0 //TODO: complete _hub_process_status_change for root hub + if (bitmap & 1) { + _hub_process_status_change(host, hub); + bitmap &= ~1; + } +#endif + + if (!bitmap) + return; + + _port_process_status_change(&host->rootport); +} +#endif + +/*===========================================================================*/ +/* Main processing loop (enumeration, loading/unloading drivers, etc). */ +/*===========================================================================*/ +void usbhMainLoop(USBHDriver *usbh) { + + if (usbh->status == USBH_STATUS_STOPPED) + return; + +#if HAL_USBH_USE_HUB + /* process root hub */ + _hub_process(usbh, NULL); + + /* process connected hubs */ + USBHHubDriver *hub; + list_for_each_entry(hub, USBHHubDriver, &usbh->hubs, node) { + _hub_process(usbh, hub); + } +#else + /* process root hub */ + _hub_process(usbh); +#endif +} + + +/*===========================================================================*/ +/* IAD class driver. */ +/*===========================================================================*/ +#if HAL_USBH_USE_IAD +static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); +static void iad_unload(usbh_baseclassdriver_t *drv); +static const usbh_classdriver_vmt_t usbhiadClassDriverVMT = { + iad_load, + iad_unload +}; +static const usbh_classdriverinfo_t usbhiadClassDriverInfo = { + 0xef, 0x02, 0x01, "IAD", &usbhiadClassDriverVMT +}; + +static usbh_baseclassdriver_t *iad_load(usbh_device_t *dev, + const uint8_t *descriptor, uint16_t rem) { + (void)rem; + + if (descriptor[1] != USBH_DT_DEVICE) + return 0; + + uinfo("Load a driver for each IF collection."); + + generic_iterator_t icfg; + if_iterator_t iif; + const usbh_ia_descriptor_t *last_iad = 0; + + cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, + dev->basicConfigDesc.wTotalLength); + if (!icfg.valid) { + uerr("Invalid configuration descriptor."); + return 0; + } + + for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { + if (iif.iad && (iif.iad != last_iad)) { + last_iad = iif.iad; + if (_classdriver_load(dev, iif.iad->bFunctionClass, + iif.iad->bFunctionSubClass, + iif.iad->bFunctionProtocol, + (uint8_t *)iif.iad, + (uint8_t *)iif.curr - (uint8_t *)iif.iad + iif.rem) != HAL_SUCCESS) { + uwarnf("No drivers found for IF collection #%d:%d", + iif.iad->bFirstInterface, + iif.iad->bFirstInterface + iif.iad->bInterfaceCount - 1); + } + } + } + + return 0; +} + +static void iad_unload(usbh_baseclassdriver_t *drv) { + (void)drv; +} +#endif + + +/*===========================================================================*/ +/* Class driver loader. */ +/*===========================================================================*/ + +static const usbh_classdriverinfo_t *usbh_classdrivers_lookup[] = { +#if HAL_USBH_USE_FTDI + &usbhftdiClassDriverInfo, +#endif +#if HAL_USBH_USE_IAD + &usbhiadClassDriverInfo, +#endif +#if HAL_USBH_USE_UVC + &usbhuvcClassDriverInfo, +#endif +#if HAL_USBH_USE_MSD + &usbhmsdClassDriverInfo, +#endif +#if HAL_USBH_USE_HUB + &usbhhubClassDriverInfo +#endif +}; + +static bool _classdriver_load(usbh_device_t *dev, uint8_t class, + uint8_t subclass, uint8_t protocol, uint8_t *descbuff, uint16_t rem) { + uint8_t i; + usbh_baseclassdriver_t *drv = NULL; + for (i = 0; i < sizeof_array(usbh_classdrivers_lookup); i++) { + const usbh_classdriverinfo_t *const info = usbh_classdrivers_lookup[i]; + if (class == 0xff) { + /* vendor specific */ + if (info->class == 0xff) { + uinfof("Try load vendor-specific driver %s", info->name); + drv = info->vmt->load(dev, descbuff, rem); + if (drv != NULL) + goto success; + } + } else if ((info->class < 0) || ((info->class == class) + && ((info->subclass < 0) || ((info->subclass == subclass) + && ((info->protocol < 0) || (info->protocol == protocol)))))) { + uinfof("Try load driver %s", info->name); + drv = info->vmt->load(dev, descbuff, rem); + +#if HAL_USBH_USE_IAD + /* special case: */ + if (info == &usbhiadClassDriverInfo) + return HAL_SUCCESS; +#endif + + if (drv != NULL) + goto success; + } + } + return HAL_FAILED; + +success: + /* Link this driver to the device */ + drv->next = dev->drivers; + dev->drivers = drv; + drv->dev = dev; + return HAL_SUCCESS; +} + +static void _classdriver_process_device(usbh_device_t *dev) { + uinfo("New device found."); + const usbh_device_descriptor_t *const devdesc = &dev->devDesc; + + usbhDevicePrintInfo(dev); + + /* TODO: Support multiple configurations + * + * Windows doesn't support them, so it's unlikely that any commercial USB device + * will have multiple configurations. + */ + if (dev->status != USBH_DEVSTATUS_CONFIGURED) { + uwarn("Multiple configurations not supported, selecting configuration #0"); + if (_device_configure(dev, 0) != HAL_SUCCESS) { + uerr("Couldn't configure device; abort."); + return; + } + } + + _device_read_full_cfgdesc(dev, dev->bConfiguration); + if (dev->fullConfigurationDescriptor == NULL) { + uerr("Couldn't read full configuration descriptor; abort."); + return; + } + + usbhDevicePrintConfiguration(dev->fullConfigurationDescriptor, + dev->basicConfigDesc.wTotalLength); + + if (devdesc->bDeviceClass == 0) { + /* each interface defines its own device class/subclass/protocol */ + uinfo("Load a driver for each IF."); + + generic_iterator_t icfg; + if_iterator_t iif; + uint8_t last_if = 0xff; + + cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, + dev->basicConfigDesc.wTotalLength); + if (!icfg.valid) { + uerr("Invalid configuration descriptor."); + goto exit; + } + + for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { + const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); + if (ifdesc->bInterfaceNumber != last_if) { + last_if = ifdesc->bInterfaceNumber; + if (_classdriver_load(dev, ifdesc->bInterfaceClass, + ifdesc->bInterfaceSubClass, + ifdesc->bInterfaceProtocol, + (uint8_t *)ifdesc, iif.rem) != HAL_SUCCESS) { + uwarnf("No drivers found for IF #%d", ifdesc->bInterfaceNumber); + } + } + } + + } else { + if (_classdriver_load(dev, devdesc->bDeviceClass, + devdesc->bDeviceSubClass, + devdesc->bDeviceProtocol, + (uint8_t *)devdesc, USBH_DT_DEVICE_SIZE) != HAL_SUCCESS) { + uwarn("No drivers found."); + } + } + +exit: + if (dev->keepFullCfgDesc == 0) { + _device_free_full_cfgdesc(dev); + } +} + + +#endif + diff --git a/os/hal/src/usbh/usbh_debug.c b/os/hal/src/usbh/hal_usbh_debug.c index 63505aa..9f17189 100644 --- a/os/hal/src/usbh/usbh_debug.c +++ b/os/hal/src/usbh/hal_usbh_debug.c @@ -1,536 +1,536 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-
-#if HAL_USE_USBH
-
-#include "ch.h"
-#include "usbh/debug.h"
-#include <stdarg.h>
-#include "chprintf.h"
-
-#if USBH_DEBUG_ENABLE
-
-#define MAX_FILLER 11
-#define FLOAT_PRECISION 9
-#define MPRINTF_USE_FLOAT 0
-
-static char *long_to_string_with_divisor(char *p, long num, unsigned radix, long divisor)
-{
- int i;
- char *q;
- long l, ll;
-
- l = num;
- if (divisor == 0) {
- ll = num;
- } else {
- ll = divisor;
- }
-
- q = p + MAX_FILLER;
- do {
- i = (int)(l % radix);
- i += '0';
- if (i > '9') {
- i += 'A' - '0' - 10;
- }
- *--q = i;
- l /= radix;
- } while ((ll /= radix) != 0);
-
- i = (int)(p + MAX_FILLER - q);
- do {
- *p++ = *q++;
- } while (--i);
-
- return p;
-}
-
-static char *ltoa(char *p, long num, unsigned radix) {
-
- return long_to_string_with_divisor(p, num, radix, 0);
-}
-
-#if MPRINTF_USE_FLOAT
-static const long _pow10[FLOAT_PRECISION] = {10, 100, 1000, 10000, 100000, 1000000,
- 10000000, 100000000, 1000000000};
-static const double m10[FLOAT_PRECISION] = {5.0/100, 5.0/1000, 5.0/10000, 5.0/100000, 5.0/1000000,
- 5.0/10000000, 5.0/100000000, 5.0/1000000000, 5.0/10000000000};
-
-static char *ftoa(char *p, double num, unsigned long precision, bool dot) {
- long l;
- char *q;
- double r;
-
-
- if (precision == 0) {
- l = (long)(num + 0.5);
- return long_to_string_with_divisor(p, l, 10, 0);
- } else {
- if (precision > FLOAT_PRECISION) precision = FLOAT_PRECISION;
- r = m10[precision - 1];
- precision = _pow10[precision - 1];
-
- l = (long)num;
- p = long_to_string_with_divisor(p, l, 10, 0);
- if (dot) *p++ = '.';
- l = (long)((num - l + r) * precision);
- q = long_to_string_with_divisor(p, l, 10, precision / 10) - 1;
-
- while (q > p) {
- if (*q != '0') {
- break;
- }
- --q;
- }
- return ++q;
- }
-
-
-
-
-}
-#endif
-
-static inline void _put(char c) {
- input_queue_t *iqp = &USBH_DEBUG_USBHD.iq;
-
- if (chIQIsFullI(iqp))
- return;
-
- iqp->q_counter++;
- *iqp->q_wrptr++ = c;
- if (iqp->q_wrptr >= iqp->q_top)
- iqp->q_wrptr = iqp->q_buffer;
-
-}
-
-int _dbg_printf(const char *fmt, va_list ap) {
- char *p, *s, c, filler;
- int i, precision, width;
- int n = 0;
- bool is_long, left_align, sign;
- long l;
-#if MPRINTF_USE_FLOAT
- double f;
- char tmpbuf[2*MAX_FILLER + 1];
-#else
- char tmpbuf[MAX_FILLER + 1];
-#endif
-
- for (;;) {
-
- //agarrar nuevo caracter de formato
- c = *fmt++;
-
- //chequeo eos
- if (c == 0) return n;
-
- //copio los caracteres comunes
- if (c != '%') {
- _put(c);
- n++;
- continue;
- }
-
- //encontré un '%'
- p = tmpbuf;
- s = tmpbuf;
-
- //left align
- left_align = FALSE;
- if (*fmt == '-') {
- fmt++;
- left_align = TRUE;
- }
-
- sign = FALSE;
- if (*fmt == '+') {
- fmt++;
- sign = TRUE;
- }
-
- //filler
- filler = ' ';
- if (*fmt == '0') {
- fmt++;
- filler = '0';
- }
-
- //width
- width = 0;
- while (TRUE) {
- c = *fmt++;
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c == '*')
- c = va_arg(ap, int);
- else
- break;
- width = width * 10 + c;
- }
-
- //precision
- precision = 0;
- if (c == '.') {
-
- if (*fmt == 'n') {
- fmt++;
-
- }
- while (TRUE) {
- c = *fmt++;
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c == '*')
- c = va_arg(ap, int);
- else
- break;
- precision = precision * 10 + c;
- }
- }
-
- //long modifier
- if (c == 'l' || c == 'L') {
- is_long = TRUE;
- if (*fmt)
- c = *fmt++;
- }
- else
- is_long = (c >= 'A') && (c <= 'Z');
-
- /* Command decoding.*/
- switch (c) {
- //char
- case 'c':
- filler = ' ';
- *p++ = va_arg(ap, int);
- break;
-
- //string
- case 's':
- filler = ' ';
- if ((s = va_arg(ap, char *)) == 0)
- s = (char *)"(null)";
- if (precision == 0)
- precision = 32767;
-
- //strlen con lÃmite hasta precision
- for (p = s; *p && (--precision >= 0); p++)
- ;
- break;
-
-
-
- case 'D':
- case 'd':
- case 'I':
- case 'i':
- if (is_long)
- l = va_arg(ap, long);
- else
- l = va_arg(ap, int);
- if (l < 0) {
- *p++ = '-';
- l = -l;
- sign = TRUE;
- } else if (sign) {
- *p++ = '+';
- }
- p = ltoa(p, l, 10);
- break;
-
-#if MPRINTF_USE_FLOAT
- case 'f':
- f = va_arg(ap, double);
- if (f < 0) {
- *p++ = '-';
- f = -f;
- sign = TRUE;
- } else if (sign) {
- *p++ = '+';
- }
- if (prec == FALSE) precision = 6;
- p = ftoa(p, f, precision, dot);
- break;
-#endif
-
-
- case 'X':
- case 'x':
- c = 16;
- goto unsigned_common;
- case 'U':
- case 'u':
- c = 10;
- goto unsigned_common;
- case 'O':
- case 'o':
- c = 8;
-
-unsigned_common:
- if (is_long)
- l = va_arg(ap, unsigned long);
- else
- l = va_arg(ap, unsigned int);
- p = ltoa(p, l, c);
- break;
-
- //copiar
- default:
- *p++ = c;
- break;
- }
-
- //longitud
- i = (int)(p - s);
-
- //calculo cuántos caracteres de filler debo poner
- if ((width -= i) < 0)
- width = 0;
-
- if (left_align == FALSE)
- width = -width;
-
- if (width < 0) {
- //alineado a la derecha
-
- //poner el signo adelante
- if (sign && filler == '0') {
- _put(*s++);
- n++;
- i--;
- }
-
- //fill a la izquierda
- do {
- _put(filler);
- n++;
- } while (++width != 0);
- }
-
- //copiar los caracteres
- while (--i >= 0) {
- _put(*s++);
- n++;
- }
-
- //fill a la derecha
- while (width) {
- _put(filler);
- n++;
- width--;
- }
- }
-
- //return n; // can raise 'code is unreachable' warning
-
-}
-
-static void _print_hdr(void)
-{
- uint32_t hfnum = USBH_DEBUG_USBHD.otg->HFNUM;
- uint16_t hfir = USBH_DEBUG_USBHD.otg->HFIR;
-
- _put(0xff);
- _put(0xff);
- _put(hfir & 0xff);
- _put(hfir >> 8);
- _put(hfnum & 0xff);
- _put((hfnum >> 8) & 0xff);
- _put((hfnum >> 16) & 0xff);
- _put((hfnum >> 24) & 0xff);
-}
-
-void usbDbgPrintf(const char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- syssts_t sts = chSysGetStatusAndLockX();
- _print_hdr();
- _dbg_printf(fmt, ap);
- _put(0);
- chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK);
- chSysRestoreStatusX(sts);
- va_end(ap);
-}
-
-
-void usbDbgPuts(const char *s)
-{
- uint32_t buff[2] = {
- 0xffff | (USBH_DEBUG_USBHD.otg->HFIR << 16),
- USBH_DEBUG_USBHD.otg->HFNUM
- };
- uint8_t *p = (uint8_t *)buff;
- uint8_t *top = p + 8;
-
- syssts_t sts = chSysGetStatusAndLockX();
- input_queue_t *iqp = &USBH_DEBUG_USBHD.iq;
- int rem = sizeof(USBH_DEBUG_USBHD.dbg_buff) - iqp->q_counter;
- while (rem) {
- *iqp->q_wrptr++ = *p;
- if (iqp->q_wrptr >= iqp->q_top)
- iqp->q_wrptr = iqp->q_buffer;
- rem--;
- if (++p == top) break;
- }
- while (rem) {
- *iqp->q_wrptr++ = *s;
- if (iqp->q_wrptr >= iqp->q_top)
- iqp->q_wrptr = iqp->q_buffer;
- rem--;
- if (!*s++) break;
- }
- iqp->q_counter = sizeof(USBH_DEBUG_USBHD.dbg_buff) - rem;
- chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK);
- chSysRestoreStatusX(sts);
-}
-
-void usbDbgReset(void) {
- const char *msg = "\r\n\r\n==== DEBUG OUTPUT RESET ====\r\n";
-
- syssts_t sts = chSysGetStatusAndLockX();
- chIQResetI(&USBH_DEBUG_USBHD.iq);
- chOQResetI(&USBH_DEBUG_SD.oqueue);
- while (*msg) {
- *USBH_DEBUG_SD.oqueue.q_wrptr++ = *msg++;
- USBH_DEBUG_SD.oqueue.q_counter--;
- }
- chSysRestoreStatusX(sts);
-}
-
-static int _get(void) {
- if (!USBH_DEBUG_USBHD.iq.q_counter) return -1;
- USBH_DEBUG_USBHD.iq.q_counter--;
- uint8_t b = *USBH_DEBUG_USBHD.iq.q_rdptr++;
- if (USBH_DEBUG_USBHD.iq.q_rdptr >= USBH_DEBUG_USBHD.iq.q_top) {
- USBH_DEBUG_USBHD.iq.q_rdptr = USBH_DEBUG_USBHD.iq.q_buffer;
- }
- return b;
-}
-
-void usbDbgSystemHalted(void) {
- while (true) {
- if (!((bool)((USBH_DEBUG_SD.oqueue.q_wrptr == USBH_DEBUG_SD.oqueue.q_rdptr) && (USBH_DEBUG_SD.oqueue.q_counter != 0U))))
- break;
- USBH_DEBUG_SD.oqueue.q_counter++;
- while (!(USART1->SR & USART_SR_TXE));
- USART1->DR = *USBH_DEBUG_SD.oqueue.q_rdptr++;
- if (USBH_DEBUG_SD.oqueue.q_rdptr >= USBH_DEBUG_SD.oqueue.q_top) {
- USBH_DEBUG_SD.oqueue.q_rdptr = USBH_DEBUG_SD.oqueue.q_buffer;
- }
- }
-
- int c;
- int state = 0;
- for (;;) {
- c = _get(); if (c < 0) break;
-
- if (state == 0) {
- if (c == 0xff) state = 1;
- } else if (state == 1) {
- if (c == 0xff) state = 2;
- else (state = 0);
- } else {
- c = _get(); if (c < 0) return;
- c = _get(); if (c < 0) return;
- c = _get(); if (c < 0) return;
- c = _get(); if (c < 0) return;
- c = _get(); if (c < 0) return;
-
- while (true) {
- c = _get(); if (c < 0) return;
- if (!c) {
- while (!(USART1->SR & USART_SR_TXE));
- USART1->DR = '\r';
- while (!(USART1->SR & USART_SR_TXE));
- USART1->DR = '\n';
- state = 0;
- break;
- }
- while (!(USART1->SR & USART_SR_TXE));
- USART1->DR = c;
- }
- }
- }
-}
-
-static void usb_debug_thread(void *p) {
- USBHDriver *host = (USBHDriver *)p;
- uint8_t state = 0;
-
- chRegSetThreadName("USBH_DBG");
- while (true) {
- msg_t c = chIQGet(&host->iq);
- if (c < 0) goto reset;
-
- if (state == 0) {
- if (c == 0xff) state = 1;
- } else if (state == 1) {
- if (c == 0xff) state = 2;
- else (state = 0);
- } else {
- uint16_t hfir;
- uint32_t hfnum;
-
- hfir = c;
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- hfir |= c << 8;
-
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- hfnum = c;
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- hfnum |= c << 8;
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- hfnum |= c << 16;
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- hfnum |= c << 24;
-
- uint32_t f = hfnum & 0xffff;
- uint32_t p = 1000 - ((hfnum >> 16) / (hfir / 1000));
- chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "%05d.%03d ", f, p);
-
- while (true) {
- c = chIQGet(&host->iq); if (c < 0) goto reset;
- if (!c) {
- sdPut(&USBH_DEBUG_SD, '\r');
- sdPut(&USBH_DEBUG_SD, '\n');
- state = 0;
- break;
- }
- sdPut(&USBH_DEBUG_SD, (uint8_t)c);
- }
- }
-
- continue;
-reset:
- state = 0;
- }
-}
-
-void usbDbgInit(USBHDriver *host) {
- if (host != &USBH_DEBUG_USBHD)
- return;
- chIQObjectInit(&USBH_DEBUG_USBHD.iq, USBH_DEBUG_USBHD.dbg_buff, sizeof(USBH_DEBUG_USBHD.dbg_buff), 0, 0);
- chThdCreateStatic(USBH_DEBUG_USBHD.waDebug, sizeof(USBH_DEBUG_USBHD.waDebug), NORMALPRIO, usb_debug_thread, &USBH_DEBUG_USBHD);
-}
-#endif
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +#if HAL_USE_USBH + +#include "ch.h" +#include "usbh/debug.h" +#include <stdarg.h> +#include "chprintf.h" + +#if USBH_DEBUG_ENABLE + +#define MAX_FILLER 11 +#define FLOAT_PRECISION 9 +#define MPRINTF_USE_FLOAT 0 + +static char *long_to_string_with_divisor(char *p, long num, unsigned radix, long divisor) +{ + int i; + char *q; + long l, ll; + + l = num; + if (divisor == 0) { + ll = num; + } else { + ll = divisor; + } + + q = p + MAX_FILLER; + do { + i = (int)(l % radix); + i += '0'; + if (i > '9') { + i += 'A' - '0' - 10; + } + *--q = i; + l /= radix; + } while ((ll /= radix) != 0); + + i = (int)(p + MAX_FILLER - q); + do { + *p++ = *q++; + } while (--i); + + return p; +} + +static char *ltoa(char *p, long num, unsigned radix) { + + return long_to_string_with_divisor(p, num, radix, 0); +} + +#if MPRINTF_USE_FLOAT +static const long _pow10[FLOAT_PRECISION] = {10, 100, 1000, 10000, 100000, 1000000, + 10000000, 100000000, 1000000000}; +static const double m10[FLOAT_PRECISION] = {5.0/100, 5.0/1000, 5.0/10000, 5.0/100000, 5.0/1000000, + 5.0/10000000, 5.0/100000000, 5.0/1000000000, 5.0/10000000000}; + +static char *ftoa(char *p, double num, unsigned long precision, bool dot) { + long l; + char *q; + double r; + + + if (precision == 0) { + l = (long)(num + 0.5); + return long_to_string_with_divisor(p, l, 10, 0); + } else { + if (precision > FLOAT_PRECISION) precision = FLOAT_PRECISION; + r = m10[precision - 1]; + precision = _pow10[precision - 1]; + + l = (long)num; + p = long_to_string_with_divisor(p, l, 10, 0); + if (dot) *p++ = '.'; + l = (long)((num - l + r) * precision); + q = long_to_string_with_divisor(p, l, 10, precision / 10) - 1; + + while (q > p) { + if (*q != '0') { + break; + } + --q; + } + return ++q; + } + + + + +} +#endif + +static inline void _put(char c) { + input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; + + if (chIQIsFullI(iqp)) + return; + + iqp->q_counter++; + *iqp->q_wrptr++ = c; + if (iqp->q_wrptr >= iqp->q_top) + iqp->q_wrptr = iqp->q_buffer; + +} + +int _dbg_printf(const char *fmt, va_list ap) { + char *p, *s, c, filler; + int i, precision, width; + int n = 0; + bool is_long, left_align, sign; + long l; +#if MPRINTF_USE_FLOAT + double f; + char tmpbuf[2*MAX_FILLER + 1]; +#else + char tmpbuf[MAX_FILLER + 1]; +#endif + + for (;;) { + + //agarrar nuevo caracter de formato + c = *fmt++; + + //chequeo eos + if (c == 0) return n; + + //copio los caracteres comunes + if (c != '%') { + _put(c); + n++; + continue; + } + + //encontré un '%' + p = tmpbuf; + s = tmpbuf; + + //left align + left_align = FALSE; + if (*fmt == '-') { + fmt++; + left_align = TRUE; + } + + sign = FALSE; + if (*fmt == '+') { + fmt++; + sign = TRUE; + } + + //filler + filler = ' '; + if (*fmt == '0') { + fmt++; + filler = '0'; + } + + //width + width = 0; + while (TRUE) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + width = width * 10 + c; + } + + //precision + precision = 0; + if (c == '.') { + + if (*fmt == 'n') { + fmt++; + + } + while (TRUE) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + precision = precision * 10 + c; + } + } + + //long modifier + if (c == 'l' || c == 'L') { + is_long = TRUE; + if (*fmt) + c = *fmt++; + } + else + is_long = (c >= 'A') && (c <= 'Z'); + + /* Command decoding.*/ + switch (c) { + //char + case 'c': + filler = ' '; + *p++ = va_arg(ap, int); + break; + + //string + case 's': + filler = ' '; + if ((s = va_arg(ap, char *)) == 0) + s = (char *)"(null)"; + if (precision == 0) + precision = 32767; + + //strlen con lÃmite hasta precision + for (p = s; *p && (--precision >= 0); p++) + ; + break; + + + + case 'D': + case 'd': + case 'I': + case 'i': + if (is_long) + l = va_arg(ap, long); + else + l = va_arg(ap, int); + if (l < 0) { + *p++ = '-'; + l = -l; + sign = TRUE; + } else if (sign) { + *p++ = '+'; + } + p = ltoa(p, l, 10); + break; + +#if MPRINTF_USE_FLOAT + case 'f': + f = va_arg(ap, double); + if (f < 0) { + *p++ = '-'; + f = -f; + sign = TRUE; + } else if (sign) { + *p++ = '+'; + } + if (prec == FALSE) precision = 6; + p = ftoa(p, f, precision, dot); + break; +#endif + + + case 'X': + case 'x': + c = 16; + goto unsigned_common; + case 'U': + case 'u': + c = 10; + goto unsigned_common; + case 'O': + case 'o': + c = 8; + +unsigned_common: + if (is_long) + l = va_arg(ap, unsigned long); + else + l = va_arg(ap, unsigned int); + p = ltoa(p, l, c); + break; + + //copiar + default: + *p++ = c; + break; + } + + //longitud + i = (int)(p - s); + + //calculo cuántos caracteres de filler debo poner + if ((width -= i) < 0) + width = 0; + + if (left_align == FALSE) + width = -width; + + if (width < 0) { + //alineado a la derecha + + //poner el signo adelante + if (sign && filler == '0') { + _put(*s++); + n++; + i--; + } + + //fill a la izquierda + do { + _put(filler); + n++; + } while (++width != 0); + } + + //copiar los caracteres + while (--i >= 0) { + _put(*s++); + n++; + } + + //fill a la derecha + while (width) { + _put(filler); + n++; + width--; + } + } + + //return n; // can raise 'code is unreachable' warning + +} + +static void _print_hdr(void) +{ + uint32_t hfnum = USBH_DEBUG_USBHD.otg->HFNUM; + uint16_t hfir = USBH_DEBUG_USBHD.otg->HFIR; + + _put(0xff); + _put(0xff); + _put(hfir & 0xff); + _put(hfir >> 8); + _put(hfnum & 0xff); + _put((hfnum >> 8) & 0xff); + _put((hfnum >> 16) & 0xff); + _put((hfnum >> 24) & 0xff); +} + +void usbDbgPrintf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + syssts_t sts = chSysGetStatusAndLockX(); + _print_hdr(); + _dbg_printf(fmt, ap); + _put(0); + chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); + chSysRestoreStatusX(sts); + va_end(ap); +} + + +void usbDbgPuts(const char *s) +{ + uint32_t buff[2] = { + 0xffff | (USBH_DEBUG_USBHD.otg->HFIR << 16), + USBH_DEBUG_USBHD.otg->HFNUM + }; + uint8_t *p = (uint8_t *)buff; + uint8_t *top = p + 8; + + syssts_t sts = chSysGetStatusAndLockX(); + input_queue_t *iqp = &USBH_DEBUG_USBHD.iq; + int rem = sizeof(USBH_DEBUG_USBHD.dbg_buff) - iqp->q_counter; + while (rem) { + *iqp->q_wrptr++ = *p; + if (iqp->q_wrptr >= iqp->q_top) + iqp->q_wrptr = iqp->q_buffer; + rem--; + if (++p == top) break; + } + while (rem) { + *iqp->q_wrptr++ = *s; + if (iqp->q_wrptr >= iqp->q_top) + iqp->q_wrptr = iqp->q_buffer; + rem--; + if (!*s++) break; + } + iqp->q_counter = sizeof(USBH_DEBUG_USBHD.dbg_buff) - rem; + chThdDequeueNextI(&USBH_DEBUG_USBHD.iq.q_waiting, Q_OK); + chSysRestoreStatusX(sts); +} + +void usbDbgReset(void) { + const char *msg = "\r\n\r\n==== DEBUG OUTPUT RESET ====\r\n"; + + syssts_t sts = chSysGetStatusAndLockX(); + chIQResetI(&USBH_DEBUG_USBHD.iq); + chOQResetI(&USBH_DEBUG_SD.oqueue); + while (*msg) { + *USBH_DEBUG_SD.oqueue.q_wrptr++ = *msg++; + USBH_DEBUG_SD.oqueue.q_counter--; + } + chSysRestoreStatusX(sts); +} + +static int _get(void) { + if (!USBH_DEBUG_USBHD.iq.q_counter) return -1; + USBH_DEBUG_USBHD.iq.q_counter--; + uint8_t b = *USBH_DEBUG_USBHD.iq.q_rdptr++; + if (USBH_DEBUG_USBHD.iq.q_rdptr >= USBH_DEBUG_USBHD.iq.q_top) { + USBH_DEBUG_USBHD.iq.q_rdptr = USBH_DEBUG_USBHD.iq.q_buffer; + } + return b; +} + +void usbDbgSystemHalted(void) { + while (true) { + if (!((bool)((USBH_DEBUG_SD.oqueue.q_wrptr == USBH_DEBUG_SD.oqueue.q_rdptr) && (USBH_DEBUG_SD.oqueue.q_counter != 0U)))) + break; + USBH_DEBUG_SD.oqueue.q_counter++; + while (!(USART1->SR & USART_SR_TXE)); + USART1->DR = *USBH_DEBUG_SD.oqueue.q_rdptr++; + if (USBH_DEBUG_SD.oqueue.q_rdptr >= USBH_DEBUG_SD.oqueue.q_top) { + USBH_DEBUG_SD.oqueue.q_rdptr = USBH_DEBUG_SD.oqueue.q_buffer; + } + } + + int c; + int state = 0; + for (;;) { + c = _get(); if (c < 0) break; + + if (state == 0) { + if (c == 0xff) state = 1; + } else if (state == 1) { + if (c == 0xff) state = 2; + else (state = 0); + } else { + c = _get(); if (c < 0) return; + c = _get(); if (c < 0) return; + c = _get(); if (c < 0) return; + c = _get(); if (c < 0) return; + c = _get(); if (c < 0) return; + + while (true) { + c = _get(); if (c < 0) return; + if (!c) { + while (!(USART1->SR & USART_SR_TXE)); + USART1->DR = '\r'; + while (!(USART1->SR & USART_SR_TXE)); + USART1->DR = '\n'; + state = 0; + break; + } + while (!(USART1->SR & USART_SR_TXE)); + USART1->DR = c; + } + } + } +} + +static void usb_debug_thread(void *p) { + USBHDriver *host = (USBHDriver *)p; + uint8_t state = 0; + + chRegSetThreadName("USBH_DBG"); + while (true) { + msg_t c = chIQGet(&host->iq); + if (c < 0) goto reset; + + if (state == 0) { + if (c == 0xff) state = 1; + } else if (state == 1) { + if (c == 0xff) state = 2; + else (state = 0); + } else { + uint16_t hfir; + uint32_t hfnum; + + hfir = c; + c = chIQGet(&host->iq); if (c < 0) goto reset; + hfir |= c << 8; + + c = chIQGet(&host->iq); if (c < 0) goto reset; + hfnum = c; + c = chIQGet(&host->iq); if (c < 0) goto reset; + hfnum |= c << 8; + c = chIQGet(&host->iq); if (c < 0) goto reset; + hfnum |= c << 16; + c = chIQGet(&host->iq); if (c < 0) goto reset; + hfnum |= c << 24; + + uint32_t f = hfnum & 0xffff; + uint32_t p = 1000 - ((hfnum >> 16) / (hfir / 1000)); + chprintf((BaseSequentialStream *)&USBH_DEBUG_SD, "%05d.%03d ", f, p); + + while (true) { + c = chIQGet(&host->iq); if (c < 0) goto reset; + if (!c) { + sdPut(&USBH_DEBUG_SD, '\r'); + sdPut(&USBH_DEBUG_SD, '\n'); + state = 0; + break; + } + sdPut(&USBH_DEBUG_SD, (uint8_t)c); + } + } + + continue; +reset: + state = 0; + } +} + +void usbDbgInit(USBHDriver *host) { + if (host != &USBH_DEBUG_USBHD) + return; + chIQObjectInit(&USBH_DEBUG_USBHD.iq, USBH_DEBUG_USBHD.dbg_buff, sizeof(USBH_DEBUG_USBHD.dbg_buff), 0, 0); + chThdCreateStatic(USBH_DEBUG_USBHD.waDebug, sizeof(USBH_DEBUG_USBHD.waDebug), NORMALPRIO, usb_debug_thread, &USBH_DEBUG_USBHD); +} +#endif + +#endif diff --git a/os/hal/src/usbh/usbh_desciter.c b/os/hal/src/usbh/hal_usbh_desciter.c index 80e4728..63137d4 100644 --- a/os/hal/src/usbh/usbh_desciter.c +++ b/os/hal/src/usbh/hal_usbh_desciter.c @@ -1,165 +1,165 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-
-#if HAL_USE_USBH
-
-#include "usbh/defs.h"
-#include "usbh/desciter.h"
-
-void cfg_iter_init(generic_iterator_t *icfg, const uint8_t *buff, uint16_t rem) {
- icfg->valid = 0;
-
- if ((buff[0] < 2) || (rem < 2) || (rem < buff[0])
- || (buff[0] < USBH_DT_CONFIG_SIZE)
- || (buff[1] != USBH_DT_CONFIG))
- return;
-
- if (rem > ((usbh_config_descriptor_t *)buff)->wTotalLength) {
- rem = ((usbh_config_descriptor_t *)buff)->wTotalLength;
- }
-
- icfg->valid = 1;
- icfg->rem = rem;
- icfg->curr = buff;
-}
-
-void if_iter_next(if_iterator_t *iif) {
- const uint8_t *curr = iif->curr;
- uint16_t rem = iif->rem;
-
- iif->valid = 0;
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- for (;;) {
- rem -= curr[0];
- curr += curr[0];
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- if (curr[1] == USBH_DT_INTERFACE_ASSOCIATION) {
- if (curr[0] < USBH_DT_INTERFACE_ASSOCIATION_SIZE)
- return;
-
- iif->iad = (usbh_ia_descriptor_t *)curr;
-
- } else if (curr[1] == USBH_DT_INTERFACE) {
- if (curr[0] < USBH_DT_INTERFACE_SIZE)
- return;
-
- if (iif->iad) {
- if ((curr[2] < iif->iad->bFirstInterface)
- || (curr[2] >= (iif->iad->bFirstInterface + iif->iad->bInterfaceCount)))
- iif->iad = 0;
- }
- break;
- }
- }
-
- iif->valid = 1;
- iif->rem = rem;
- iif->curr = curr;
-}
-
-void if_iter_init(if_iterator_t *iif, const generic_iterator_t *icfg) {
- iif->iad = 0;
- iif->curr = icfg->curr;
- iif->rem = icfg->rem;
- if_iter_next(iif);
-}
-
-void ep_iter_next(generic_iterator_t *iep) {
- const uint8_t *curr = iep->curr;
- uint16_t rem = iep->rem;
-
- iep->valid = 0;
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- for (;;) {
- rem -= curr[0];
- curr += curr[0];
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
- || (curr[1] == USBH_DT_INTERFACE)
- || (curr[1] == USBH_DT_CONFIG)) {
- return;
- } else if (curr[1] == USBH_DT_ENDPOINT) {
- if (curr[0] < USBH_DT_ENDPOINT_SIZE)
- return;
-
- break;
- }
- }
-
- iep->valid = 1;
- iep->rem = rem;
- iep->curr = curr;
-}
-
-void ep_iter_init(generic_iterator_t *iep, const if_iterator_t *iif) {
- iep->curr = iif->curr;
- iep->rem = iif->rem;
- ep_iter_next(iep);
-}
-
-void cs_iter_next(generic_iterator_t *ics) {
- const uint8_t *curr = ics->curr;
- uint16_t rem = ics->rem;
-
- ics->valid = 0;
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- //for (;;) {
- rem -= curr[0];
- curr += curr[0];
-
- if ((curr[0] < 2) || (rem < 2) || (rem < curr[0]))
- return;
-
- if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION)
- || (curr[1] == USBH_DT_INTERFACE)
- || (curr[1] == USBH_DT_CONFIG)
- || (curr[1] == USBH_DT_ENDPOINT)) {
- return;
- }
-
- // break;
- //}
-
- ics->valid = 1;
- ics->rem = rem;
- ics->curr = curr;
-}
-
-void cs_iter_init(generic_iterator_t *ics, const generic_iterator_t *iter) {
- ics->curr = iter->curr;
- ics->rem = iter->rem;
- cs_iter_next(ics);
-}
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" + +#if HAL_USE_USBH + +#include "usbh/defs.h" +#include "usbh/desciter.h" + +void cfg_iter_init(generic_iterator_t *icfg, const uint8_t *buff, uint16_t rem) { + icfg->valid = 0; + + if ((buff[0] < 2) || (rem < 2) || (rem < buff[0]) + || (buff[0] < USBH_DT_CONFIG_SIZE) + || (buff[1] != USBH_DT_CONFIG)) + return; + + if (rem > ((usbh_config_descriptor_t *)buff)->wTotalLength) { + rem = ((usbh_config_descriptor_t *)buff)->wTotalLength; + } + + icfg->valid = 1; + icfg->rem = rem; + icfg->curr = buff; +} + +void if_iter_next(if_iterator_t *iif) { + const uint8_t *curr = iif->curr; + uint16_t rem = iif->rem; + + iif->valid = 0; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + for (;;) { + rem -= curr[0]; + curr += curr[0]; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + if (curr[1] == USBH_DT_INTERFACE_ASSOCIATION) { + if (curr[0] < USBH_DT_INTERFACE_ASSOCIATION_SIZE) + return; + + iif->iad = (usbh_ia_descriptor_t *)curr; + + } else if (curr[1] == USBH_DT_INTERFACE) { + if (curr[0] < USBH_DT_INTERFACE_SIZE) + return; + + if (iif->iad) { + if ((curr[2] < iif->iad->bFirstInterface) + || (curr[2] >= (iif->iad->bFirstInterface + iif->iad->bInterfaceCount))) + iif->iad = 0; + } + break; + } + } + + iif->valid = 1; + iif->rem = rem; + iif->curr = curr; +} + +void if_iter_init(if_iterator_t *iif, const generic_iterator_t *icfg) { + iif->iad = 0; + iif->curr = icfg->curr; + iif->rem = icfg->rem; + if_iter_next(iif); +} + +void ep_iter_next(generic_iterator_t *iep) { + const uint8_t *curr = iep->curr; + uint16_t rem = iep->rem; + + iep->valid = 0; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + for (;;) { + rem -= curr[0]; + curr += curr[0]; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION) + || (curr[1] == USBH_DT_INTERFACE) + || (curr[1] == USBH_DT_CONFIG)) { + return; + } else if (curr[1] == USBH_DT_ENDPOINT) { + if (curr[0] < USBH_DT_ENDPOINT_SIZE) + return; + + break; + } + } + + iep->valid = 1; + iep->rem = rem; + iep->curr = curr; +} + +void ep_iter_init(generic_iterator_t *iep, const if_iterator_t *iif) { + iep->curr = iif->curr; + iep->rem = iif->rem; + ep_iter_next(iep); +} + +void cs_iter_next(generic_iterator_t *ics) { + const uint8_t *curr = ics->curr; + uint16_t rem = ics->rem; + + ics->valid = 0; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + //for (;;) { + rem -= curr[0]; + curr += curr[0]; + + if ((curr[0] < 2) || (rem < 2) || (rem < curr[0])) + return; + + if ((curr[1] == USBH_DT_INTERFACE_ASSOCIATION) + || (curr[1] == USBH_DT_INTERFACE) + || (curr[1] == USBH_DT_CONFIG) + || (curr[1] == USBH_DT_ENDPOINT)) { + return; + } + + // break; + //} + + ics->valid = 1; + ics->rem = rem; + ics->curr = curr; +} + +void cs_iter_init(generic_iterator_t *ics, const generic_iterator_t *iter) { + ics->curr = iter->curr; + ics->rem = iter->rem; + cs_iter_next(ics); +} + +#endif diff --git a/os/hal/src/usbh/usbh_ftdi.c b/os/hal/src/usbh/hal_usbh_ftdi.c index cdf3410..4bd7296 100644 --- a/os/hal/src/usbh/usbh_ftdi.c +++ b/os/hal/src/usbh/hal_usbh_ftdi.c @@ -1,717 +1,717 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-#include "usbh.h"
-
-#if HAL_USBH_USE_FTDI
-
-#if !HAL_USE_USBH
-#error "USBHFTDI needs USBH"
-#endif
-
-#include <string.h>
-#include "usbh/dev/ftdi.h"
-#include "usbh/internal.h"
-
-//#pragma GCC optimize("Og")
-
-
-#if USBHFTDI_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBHFTDI_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBHFTDI_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBHFTDI_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-
-/*===========================================================================*/
-/* USB Class driver loader for FTDI */
-/*===========================================================================*/
-USBHFTDIDriver USBHFTDID[HAL_USBHFTDI_MAX_INSTANCES];
-
-static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
-static void _ftdi_unload(usbh_baseclassdriver_t *drv);
-
-static const usbh_classdriver_vmt_t class_driver_vmt = {
- _ftdi_load,
- _ftdi_unload
-};
-
-const usbh_classdriverinfo_t usbhftdiClassDriverInfo = {
- 0xff, 0xff, 0xff, "FTDI", &class_driver_vmt
-};
-
-static USBHFTDIPortDriver *_find_port(void) {
- uint8_t i;
- for (i = 0; i < HAL_USBHFTDI_MAX_PORTS; i++) {
- if (FTDIPD[i].ftdip == NULL)
- return &FTDIPD[i];
- }
- return NULL;
-}
-
-static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
- int i;
- USBHFTDIDriver *ftdip;
-
- if (dev->devDesc.idVendor != 0x0403) {
- uerr("FTDI: Unrecognized VID");
- return NULL;
- }
-
- switch (dev->devDesc.idProduct) {
- case 0x6001:
- case 0x6010:
- case 0x6011:
- case 0x6014:
- case 0x6015:
- break;
- default:
- uerr("FTDI: Unrecognized PID");
- return NULL;
- }
-
- if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
- return NULL;
-
- const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t * const)descriptor;
- if (ifdesc->bInterfaceNumber != 0) {
- uwarn("FTDI: Will allocate driver along with IF #0");
- }
-
- /* alloc driver */
- for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) {
- if (USBHFTDID[i].dev == NULL) {
- ftdip = &USBHFTDID[i];
- goto alloc_ok;
- }
- }
-
- uwarn("FTDI: Can't alloc driver");
-
- /* can't alloc */
- return NULL;
-
-alloc_ok:
- /* initialize the driver's variables */
- ftdip->ports = 0;
- switch (dev->devDesc.bcdDevice) {
- case 0x200: //AM
- uinfo("FTDI: Type A chip");
- ftdip->type = USBHFTDI_TYPE_A;
- break;
- case 0x400: //BM
- case 0x500: //2232C
- case 0x600: //R
- case 0x1000: //230X
- uinfo("FTDI: Type B chip");
- ftdip->type = USBHFTDI_TYPE_B;
- break;
- case 0x700: //2232H;
- case 0x800: //4232H;
- case 0x900: //232H;
- uinfo("FTDI: Type H chip");
- ftdip->type = USBHFTDI_TYPE_H;
- default:
- uerr("FTDI: Unrecognized chip type");
- return NULL;
- }
- usbhEPSetName(&dev->ctrl, "FTD[CTRL]");
-
- /* parse the configuration descriptor */
- generic_iterator_t iep, icfg;
- if_iterator_t iif;
- cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength);
- for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) {
- const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
- uinfof("FTDI: Interface #%d", ifdesc->bInterfaceNumber);
-
- USBHFTDIPortDriver *const prt = _find_port();
- if (prt == NULL) {
- uwarn("\tCan't alloc port for this interface");
- break;
- }
-
- prt->ifnum = ifdesc->bInterfaceNumber;
- prt->epin.status = USBH_EPSTATUS_UNINITIALIZED;
- prt->epout.status = USBH_EPSTATUS_UNINITIALIZED;
-
- for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
- const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
- if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
- uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
- usbhEPObjectInit(&prt->epin, dev, epdesc);
- usbhEPSetName(&prt->epin, "FTD[BIN ]");
- } else if (((epdesc->bEndpointAddress & 0x80) == 0)
- && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
- uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
- usbhEPObjectInit(&prt->epout, dev, epdesc);
- usbhEPSetName(&prt->epout, "FTD[BOUT]");
- } else {
- uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
- epdesc->bEndpointAddress, epdesc->bmAttributes);
- }
- }
-
- if ((prt->epin.status != USBH_EPSTATUS_CLOSED)
- || (prt->epout.status != USBH_EPSTATUS_CLOSED)) {
- uwarn("\tCouldn't find endpoints; can't alloc port for this interface");
- continue;
- }
-
- /* link the new block driver to the list */
- prt->next = ftdip->ports;
- ftdip->ports = prt;
- prt->ftdip = ftdip;
-
- prt->state = USBHFTDIP_STATE_ACTIVE;
- }
-
- return (usbh_baseclassdriver_t *)ftdip;
-
-}
-
-static void _stop(USBHFTDIPortDriver *ftdipp);
-static void _ftdi_unload(usbh_baseclassdriver_t *drv) {
- osalDbgCheck(drv != NULL);
- USBHFTDIDriver *const ftdip = (USBHFTDIDriver *)drv;
- USBHFTDIPortDriver *ftdipp = ftdip->ports;
-
- osalMutexLock(&ftdip->mtx);
- while (ftdipp) {
- _stop(ftdipp);
- ftdipp = ftdipp->next;
- }
-
- ftdipp = ftdip->ports;
- osalSysLock();
- while (ftdipp) {
- USBHFTDIPortDriver *next = ftdipp->next;
- usbhftdipObjectInit(ftdipp);
- ftdipp = next;
- }
- osalSysUnlock();
- osalMutexUnlock(&ftdip->mtx);
-}
-
-
-USBHFTDIPortDriver FTDIPD[HAL_USBHFTDI_MAX_PORTS];
-
-
-#define FTDI_COMMAND_RESET 0
-#define FTDI_RESET_ALL 0
-#define FTDI_RESET_PURGE_RX 1
-#define FTDI_RESET_PURGE_TX 2
-
-#define FTDI_COMMAND_SETFLOW 2
-
-#define FTDI_COMMAND_SETBAUD 3
-
-#define FTDI_COMMAND_SETDATA 4
-#define FTDI_SETDATA_BREAK (0x1 << 14)
-
-#if 0
-#define FTDI_COMMAND_MODEMCTRL 1
-#define FTDI_COMMAND_GETMODEMSTATUS 5 /* Retrieve current value of modem status register */
-#define FTDI_COMMAND_SETEVENTCHAR 6 /* Set the event character */
-#define FTDI_COMMAND_SETERRORCHAR 7 /* Set the error character */
-#define FTDI_COMMAND_SETLATENCYTIMER 9 /* Set the latency timer */
-#define FTDI_COMMAND_GETLATENCYTIMER 10 /* Get the latency timer */
-#endif
-
-/*
- * DATA FORMAT
- *
- * IN Endpoint
- *
- * The device reserves the first two bytes of data on this endpoint to contain
- * the current values of the modem and line status registers. In the absence of
- * data, the device generates a message consisting of these two status bytes
- * every 40 ms
- *
- * Byte 0: Modem Status
- *
- * Offset Description
- * B0 Reserved - must be 1
- * B1 Reserved - must be 0
- * B2 Reserved - must be 0
- * B3 Reserved - must be 0
- * B4 Clear to Send (CTS)
- * B5 Data Set Ready (DSR)
- * B6 Ring Indicator (RI)
- * B7 Receive Line Signal Detect (RLSD)
- *
- * Byte 1: Line Status
- *
- * Offset Description
- * B0 Data Ready (DR)
- * B1 Overrun Error (OE)
- * B2 Parity Error (PE)
- * B3 Framing Error (FE)
- * B4 Break Interrupt (BI)
- * B5 Transmitter Holding Register (THRE)
- * B6 Transmitter Empty (TEMT)
- * B7 Error in RCVR FIFO
- *
- */
-#define FTDI_RS0_CTS (1 << 4)
-#define FTDI_RS0_DSR (1 << 5)
-#define FTDI_RS0_RI (1 << 6)
-#define FTDI_RS0_RLSD (1 << 7)
-
-#define FTDI_RS_DR 1
-#define FTDI_RS_OE (1<<1)
-#define FTDI_RS_PE (1<<2)
-#define FTDI_RS_FE (1<<3)
-#define FTDI_RS_BI (1<<4)
-#define FTDI_RS_THRE (1<<5)
-#define FTDI_RS_TEMT (1<<6)
-#define FTDI_RS_FIFO (1<<7)
-
-
-static usbh_urbstatus_t _ftdi_port_control(USBHFTDIPortDriver *ftdipp,
- uint8_t bRequest, uint8_t wValue, uint8_t bHIndex, uint16_t wLength,
- uint8_t *buff) {
-
- static const uint8_t bmRequestType[] = {
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //0 FTDI_COMMAND_RESET
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //1 FTDI_COMMAND_MODEMCTRL
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //2 FTDI_COMMAND_SETFLOW
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //3 FTDI_COMMAND_SETBAUD
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //4 FTDI_COMMAND_SETDATA
- };
-
- osalDbgCheck(bRequest < sizeof_array(bmRequestType));
- osalDbgCheck(bRequest != 1);
-
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
- bmRequestType[bRequest],
- bRequest,
- wValue,
- (bHIndex << 8) | (ftdipp->ifnum + 1),
- wLength
- };
-
- return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, buff, NULL, MS2ST(1000));
-}
-
-static uint32_t _get_divisor(uint32_t baud, usbhftdi_type_t type) {
- static const uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7};
- uint32_t divisor;
-
- if (type == USBHFTDI_TYPE_A) {
- uint32_t divisor3 = ((48000000UL / 2) + baud / 2) / baud;
- uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor3);
- if ((divisor3 & 0x7) == 7)
- divisor3++; /* round x.7/8 up to x+1 */
-
- divisor = divisor3 >> 3;
- divisor3 &= 0x7;
- if (divisor3 == 1)
- divisor |= 0xc000;
- else if (divisor3 >= 4)
- divisor |= 0x4000;
- else if (divisor3 != 0)
- divisor |= 0x8000;
- else if (divisor == 1)
- divisor = 0; /* special case for maximum baud rate */
- } else {
- if (type == USBHFTDI_TYPE_B) {
- divisor = ((48000000UL / 2) + baud / 2) / baud;
- uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor);
- } else {
- /* hi-speed baud rate is 10-bit sampling instead of 16-bit */
- if (baud < 1200)
- baud = 1200;
- divisor = (120000000UL * 8 + baud * 5) / (baud * 10);
- uinfof("FTDI: desired=%dbps, real=%dbps", baud, (120000000UL * 8) / divisor / 10);
- }
- divisor = (divisor >> 3) | (divfrac[divisor & 0x7] << 14);
-
- /* Deal with special cases for highest baud rates. */
- if (divisor == 1)
- divisor = 0;
- else if (divisor == 0x4001)
- divisor = 1;
-
- if (type == USBHFTDI_TYPE_H)
- divisor |= 0x00020000;
- }
- return divisor;
-}
-
-static usbh_urbstatus_t _set_baudrate(USBHFTDIPortDriver *ftdipp, uint32_t baudrate) {
- uint32_t divisor = _get_divisor(baudrate, ftdipp->ftdip->type);
- uint16_t wValue = (uint16_t)divisor;
- uint16_t wIndex = (uint16_t)(divisor >> 16);
- if (ftdipp->ftdip->dev->basicConfigDesc.bNumInterfaces > 1)
- wIndex = (wIndex << 8) | (ftdipp->ifnum + 1);
-
- const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = {
- USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE,
- FTDI_COMMAND_SETBAUD,
- wValue,
- wIndex,
- 0
- };
- return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, NULL, NULL, MS2ST(1000));
-}
-
-
-static void _submitOutI(USBHFTDIPortDriver *ftdipp, uint32_t len) {
- udbgf("FTDI: Submit OUT %d", len);
- ftdipp->oq_urb.requestedLength = len;
- usbhURBObjectResetI(&ftdipp->oq_urb);
- usbhURBSubmitI(&ftdipp->oq_urb);
-}
-
-static void _out_cb(usbh_urb_t *urb) {
- USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData;
- switch (urb->status) {
- case USBH_URBSTATUS_OK:
- ftdipp->oq_ptr = ftdipp->oq_buff;
- ftdipp->oq_counter = 64;
- chThdDequeueNextI(&ftdipp->oq_waiting, Q_OK);
- return;
- case USBH_URBSTATUS_DISCONNECTED:
- uwarn("FTDI: URB OUT disconnected");
- chThdDequeueNextI(&ftdipp->oq_waiting, Q_RESET);
- return;
- default:
- uerrf("FTDI: URB OUT status unexpected = %d", urb->status);
- break;
- }
- usbhURBObjectResetI(&ftdipp->oq_urb);
- usbhURBSubmitI(&ftdipp->oq_urb);
-}
-
-static size_t _write_timeout(USBHFTDIPortDriver *ftdipp, const uint8_t *bp,
- size_t n, systime_t timeout) {
- chDbgCheck(n > 0U);
-
- size_t w = 0;
- chSysLock();
- while (true) {
- if (ftdipp->state != USBHFTDIP_STATE_READY) {
- chSysUnlock();
- return w;
- }
- while (usbhURBIsBusy(&ftdipp->oq_urb)) {
- if (chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout) != Q_OK) {
- chSysUnlock();
- return w;
- }
- }
-
- *ftdipp->oq_ptr++ = *bp++;
- if (--ftdipp->oq_counter == 0) {
- _submitOutI(ftdipp, 64);
- chSchRescheduleS();
- }
- chSysUnlock(); /* Gives a preemption chance in a controlled point.*/
-
- w++;
- if (--n == 0U)
- return w;
-
- chSysLock();
- }
-}
-
-static msg_t _put_timeout(USBHFTDIPortDriver *ftdipp, uint8_t b, systime_t timeout) {
-
- chSysLock();
- if (ftdipp->state != USBHFTDIP_STATE_READY) {
- chSysUnlock();
- return Q_RESET;
- }
-
- while (usbhURBIsBusy(&ftdipp->oq_urb)) {
- msg_t msg = chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout);
- if (msg < Q_OK) {
- chSysUnlock();
- return msg;
- }
- }
-
- *ftdipp->oq_ptr++ = b;
- if (--ftdipp->oq_counter == 0) {
- _submitOutI(ftdipp, 64);
- chSchRescheduleS();
- }
- chSysUnlock();
- return Q_OK;
-}
-
-static size_t _write(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, size_t n) {
- return _write_timeout(ftdipp, bp, n, TIME_INFINITE);
-}
-
-static msg_t _put(USBHFTDIPortDriver *ftdipp, uint8_t b) {
- return _put_timeout(ftdipp, b, TIME_INFINITE);
-}
-
-static void _submitInI(USBHFTDIPortDriver *ftdipp) {
- udbg("FTDI: Submit IN");
- usbhURBObjectResetI(&ftdipp->iq_urb);
- usbhURBSubmitI(&ftdipp->iq_urb);
-}
-
-static void _in_cb(usbh_urb_t *urb) {
- USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData;
- switch (urb->status) {
- case USBH_URBSTATUS_OK:
- if (urb->actualLength < 2) {
- uwarnf("FTDI: URB IN actualLength = %d, < 2", urb->actualLength);
- } else if (urb->actualLength > 2) {
- udbgf("FTDI: URB IN data len=%d, status=%02x %02x",
- urb->actualLength - 2,
- ((uint8_t *)urb->buff)[0],
- ((uint8_t *)urb->buff)[1]);
- ftdipp->iq_ptr = ftdipp->iq_buff + 2;
- ftdipp->iq_counter = urb->actualLength - 2;
- chThdDequeueNextI(&ftdipp->iq_waiting, Q_OK);
- return;
- } else {
- udbgf("FTDI: URB IN no data, status=%02x %02x",
- ((uint8_t *)urb->buff)[0],
- ((uint8_t *)urb->buff)[1]);
- return;
- }
- break;
- case USBH_URBSTATUS_DISCONNECTED:
- uwarn("FTDI: URB IN disconnected");
- chThdDequeueNextI(&ftdipp->iq_waiting, Q_RESET);
- return;
- default:
- uerrf("FTDI: URB IN status unexpected = %d", urb->status);
- break;
- }
- _submitInI(ftdipp);
-}
-
-static size_t _read_timeout(USBHFTDIPortDriver *ftdipp, uint8_t *bp,
- size_t n, systime_t timeout) {
- size_t r = 0;
-
- chDbgCheck(n > 0U);
-
- chSysLock();
- while (true) {
- if (ftdipp->state != USBHFTDIP_STATE_READY) {
- chSysUnlock();
- return r;
- }
- while (ftdipp->iq_counter == 0) {
- if (!usbhURBIsBusy(&ftdipp->iq_urb))
- _submitInI(ftdipp);
- if (chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout) != Q_OK) {
- chSysUnlock();
- return r;
- }
- }
- *bp++ = *ftdipp->iq_ptr++;
- if (--ftdipp->iq_counter == 0) {
- _submitInI(ftdipp);
- chSchRescheduleS();
- }
- chSysUnlock();
-
- r++;
- if (--n == 0U)
- return r;
-
- chSysLock();
- }
-}
-
-static msg_t _get_timeout(USBHFTDIPortDriver *ftdipp, systime_t timeout) {
- uint8_t b;
-
- chSysLock();
- if (ftdipp->state != USBHFTDIP_STATE_READY) {
- chSysUnlock();
- return Q_RESET;
- }
- while (ftdipp->iq_counter == 0) {
- if (!usbhURBIsBusy(&ftdipp->iq_urb))
- _submitInI(ftdipp);
- msg_t msg = chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout);
- if (msg < Q_OK) {
- chSysUnlock();
- return msg;
- }
- }
- b = *ftdipp->iq_ptr++;
- if (--ftdipp->iq_counter == 0) {
- _submitInI(ftdipp);
- chSchRescheduleS();
- }
- chSysUnlock();
-
- return (msg_t)b;
-}
-
-static msg_t _get(USBHFTDIPortDriver *ftdipp) {
- return _get_timeout(ftdipp, TIME_INFINITE);
-}
-
-static size_t _read(USBHFTDIPortDriver *ftdipp, uint8_t *bp, size_t n) {
- return _read_timeout(ftdipp, bp, n, TIME_INFINITE);
-}
-
-static void _vt(void *p) {
- USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)p;
- chSysLockFromISR();
- uint32_t len = ftdipp->oq_ptr - ftdipp->oq_buff;
- if (len && !usbhURBIsBusy(&ftdipp->oq_urb)) {
- _submitOutI(ftdipp, len);
- }
- if ((ftdipp->iq_counter == 0) && !usbhURBIsBusy(&ftdipp->iq_urb)) {
- _submitInI(ftdipp);
- }
- chVTSetI(&ftdipp->vt, MS2ST(16), _vt, ftdipp);
- chSysUnlockFromISR();
-}
-
-static const struct FTDIPortDriverVMT async_channel_vmt = {
- (size_t (*)(void *, const uint8_t *, size_t))_write,
- (size_t (*)(void *, uint8_t *, size_t))_read,
- (msg_t (*)(void *, uint8_t))_put,
- (msg_t (*)(void *))_get,
- (msg_t (*)(void *, uint8_t, systime_t))_put_timeout,
- (msg_t (*)(void *, systime_t))_get_timeout,
- (size_t (*)(void *, const uint8_t *, size_t, systime_t))_write_timeout,
- (size_t (*)(void *, uint8_t *, size_t, systime_t))_read_timeout
-};
-
-
-static void _stop(USBHFTDIPortDriver *ftdipp) {
- osalSysLock();
- chVTResetI(&ftdipp->vt);
- usbhEPCloseS(&ftdipp->epin);
- usbhEPCloseS(&ftdipp->epout);
- chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET);
- chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET);
- osalOsRescheduleS();
- ftdipp->state = USBHFTDIP_STATE_ACTIVE;
- osalSysUnlock();
-}
-
-void usbhftdipStop(USBHFTDIPortDriver *ftdipp) {
- osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE)
- || (ftdipp->state == USBHFTDIP_STATE_READY));
-
- if (ftdipp->state == USBHFTDIP_STATE_ACTIVE) {
- return;
- }
-
- osalMutexLock(&ftdipp->ftdip->mtx);
- _stop(ftdipp);
- osalMutexUnlock(&ftdipp->ftdip->mtx);
-}
-
-void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config) {
- static const USBHFTDIPortConfig default_config = {
- HAL_USBHFTDI_DEFAULT_SPEED,
- HAL_USBHFTDI_DEFAULT_FRAMING,
- HAL_USBHFTDI_DEFAULT_HANDSHAKE,
- HAL_USBHFTDI_DEFAULT_XON,
- HAL_USBHFTDI_DEFAULT_XOFF
- };
-
- osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE)
- || (ftdipp->state == USBHFTDIP_STATE_READY));
-
- if (ftdipp->state == USBHFTDIP_STATE_READY)
- return;
-
- osalMutexLock(&ftdipp->ftdip->mtx);
- if (config == NULL)
- config = &default_config;
-
- uint16_t wValue = 0;
- _ftdi_port_control(ftdipp, FTDI_COMMAND_RESET, FTDI_RESET_ALL, 0, 0, NULL);
- _set_baudrate(ftdipp, config->speed);
- _ftdi_port_control(ftdipp, FTDI_COMMAND_SETDATA, config->framing, 0, 0, NULL);
- if (config->handshake & USBHFTDI_HANDSHAKE_XON_XOFF)
- wValue = (config->xoff_character << 8) | config->xon_character;
- _ftdi_port_control(ftdipp, FTDI_COMMAND_SETFLOW, wValue, config->handshake, 0, NULL);
-
- usbhURBObjectInit(&ftdipp->oq_urb, &ftdipp->epout, _out_cb, ftdipp, ftdipp->oq_buff, 0);
- chThdQueueObjectInit(&ftdipp->oq_waiting);
- ftdipp->oq_counter = 64;
- ftdipp->oq_ptr = ftdipp->oq_buff;
- usbhEPOpen(&ftdipp->epout);
-
- usbhURBObjectInit(&ftdipp->iq_urb, &ftdipp->epin, _in_cb, ftdipp, ftdipp->iq_buff, 64);
- chThdQueueObjectInit(&ftdipp->iq_waiting);
- ftdipp->iq_counter = 0;
- ftdipp->iq_ptr = ftdipp->iq_buff;
- usbhEPOpen(&ftdipp->epin);
- osalSysLock();
- usbhURBSubmitI(&ftdipp->iq_urb);
- osalSysUnlock();
-
- chVTObjectInit(&ftdipp->vt);
- chVTSet(&ftdipp->vt, MS2ST(16), _vt, ftdipp);
-
- ftdipp->state = USBHFTDIP_STATE_READY;
- osalMutexUnlock(&ftdipp->ftdip->mtx);
-}
-
-void usbhftdiObjectInit(USBHFTDIDriver *ftdip) {
- osalDbgCheck(ftdip != NULL);
- memset(ftdip, 0, sizeof(*ftdip));
- ftdip->info = &usbhftdiClassDriverInfo;
- osalMutexObjectInit(&ftdip->mtx);
-}
-
-void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp) {
- osalDbgCheck(ftdipp != NULL);
- memset(ftdipp, 0, sizeof(*ftdipp));
- ftdipp->vmt = &async_channel_vmt;
- ftdipp->state = USBHFTDIP_STATE_STOP;
-}
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "hal_usbh.h" + +#if HAL_USBH_USE_FTDI + +#if !HAL_USE_USBH +#error "USBHFTDI needs USBH" +#endif + +#include <string.h> +#include "usbh/dev/ftdi.h" +#include "usbh/internal.h" + +//#pragma GCC optimize("Og") + + +#if USBHFTDI_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBHFTDI_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBHFTDI_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBHFTDI_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + + +/*===========================================================================*/ +/* USB Class driver loader for FTDI */ +/*===========================================================================*/ +USBHFTDIDriver USBHFTDID[HAL_USBHFTDI_MAX_INSTANCES]; + +static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); +static void _ftdi_unload(usbh_baseclassdriver_t *drv); + +static const usbh_classdriver_vmt_t class_driver_vmt = { + _ftdi_load, + _ftdi_unload +}; + +const usbh_classdriverinfo_t usbhftdiClassDriverInfo = { + 0xff, 0xff, 0xff, "FTDI", &class_driver_vmt +}; + +static USBHFTDIPortDriver *_find_port(void) { + uint8_t i; + for (i = 0; i < HAL_USBHFTDI_MAX_PORTS; i++) { + if (FTDIPD[i].ftdip == NULL) + return &FTDIPD[i]; + } + return NULL; +} + +static usbh_baseclassdriver_t *_ftdi_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { + int i; + USBHFTDIDriver *ftdip; + + if (dev->devDesc.idVendor != 0x0403) { + uerr("FTDI: Unrecognized VID"); + return NULL; + } + + switch (dev->devDesc.idProduct) { + case 0x6001: + case 0x6010: + case 0x6011: + case 0x6014: + case 0x6015: + break; + default: + uerr("FTDI: Unrecognized PID"); + return NULL; + } + + if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) + return NULL; + + const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t * const)descriptor; + if (ifdesc->bInterfaceNumber != 0) { + uwarn("FTDI: Will allocate driver along with IF #0"); + } + + /* alloc driver */ + for (i = 0; i < HAL_USBHFTDI_MAX_INSTANCES; i++) { + if (USBHFTDID[i].dev == NULL) { + ftdip = &USBHFTDID[i]; + goto alloc_ok; + } + } + + uwarn("FTDI: Can't alloc driver"); + + /* can't alloc */ + return NULL; + +alloc_ok: + /* initialize the driver's variables */ + ftdip->ports = 0; + switch (dev->devDesc.bcdDevice) { + case 0x200: //AM + uinfo("FTDI: Type A chip"); + ftdip->type = USBHFTDI_TYPE_A; + break; + case 0x400: //BM + case 0x500: //2232C + case 0x600: //R + case 0x1000: //230X + uinfo("FTDI: Type B chip"); + ftdip->type = USBHFTDI_TYPE_B; + break; + case 0x700: //2232H; + case 0x800: //4232H; + case 0x900: //232H; + uinfo("FTDI: Type H chip"); + ftdip->type = USBHFTDI_TYPE_H; + default: + uerr("FTDI: Unrecognized chip type"); + return NULL; + } + usbhEPSetName(&dev->ctrl, "FTD[CTRL]"); + + /* parse the configuration descriptor */ + generic_iterator_t iep, icfg; + if_iterator_t iif; + cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, dev->basicConfigDesc.wTotalLength); + for (if_iter_init(&iif, &icfg); iif.valid; if_iter_next(&iif)) { + const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); + uinfof("FTDI: Interface #%d", ifdesc->bInterfaceNumber); + + USBHFTDIPortDriver *const prt = _find_port(); + if (prt == NULL) { + uwarn("\tCan't alloc port for this interface"); + break; + } + + prt->ifnum = ifdesc->bInterfaceNumber; + prt->epin.status = USBH_EPSTATUS_UNINITIALIZED; + prt->epout.status = USBH_EPSTATUS_UNINITIALIZED; + + for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) { + const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep); + if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) { + uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress); + usbhEPObjectInit(&prt->epin, dev, epdesc); + usbhEPSetName(&prt->epin, "FTD[BIN ]"); + } else if (((epdesc->bEndpointAddress & 0x80) == 0) + && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) { + uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress); + usbhEPObjectInit(&prt->epout, dev, epdesc); + usbhEPSetName(&prt->epout, "FTD[BOUT]"); + } else { + uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x", + epdesc->bEndpointAddress, epdesc->bmAttributes); + } + } + + if ((prt->epin.status != USBH_EPSTATUS_CLOSED) + || (prt->epout.status != USBH_EPSTATUS_CLOSED)) { + uwarn("\tCouldn't find endpoints; can't alloc port for this interface"); + continue; + } + + /* link the new block driver to the list */ + prt->next = ftdip->ports; + ftdip->ports = prt; + prt->ftdip = ftdip; + + prt->state = USBHFTDIP_STATE_ACTIVE; + } + + return (usbh_baseclassdriver_t *)ftdip; + +} + +static void _stop(USBHFTDIPortDriver *ftdipp); +static void _ftdi_unload(usbh_baseclassdriver_t *drv) { + osalDbgCheck(drv != NULL); + USBHFTDIDriver *const ftdip = (USBHFTDIDriver *)drv; + USBHFTDIPortDriver *ftdipp = ftdip->ports; + + osalMutexLock(&ftdip->mtx); + while (ftdipp) { + _stop(ftdipp); + ftdipp = ftdipp->next; + } + + ftdipp = ftdip->ports; + osalSysLock(); + while (ftdipp) { + USBHFTDIPortDriver *next = ftdipp->next; + usbhftdipObjectInit(ftdipp); + ftdipp = next; + } + osalSysUnlock(); + osalMutexUnlock(&ftdip->mtx); +} + + +USBHFTDIPortDriver FTDIPD[HAL_USBHFTDI_MAX_PORTS]; + + +#define FTDI_COMMAND_RESET 0 +#define FTDI_RESET_ALL 0 +#define FTDI_RESET_PURGE_RX 1 +#define FTDI_RESET_PURGE_TX 2 + +#define FTDI_COMMAND_SETFLOW 2 + +#define FTDI_COMMAND_SETBAUD 3 + +#define FTDI_COMMAND_SETDATA 4 +#define FTDI_SETDATA_BREAK (0x1 << 14) + +#if 0 +#define FTDI_COMMAND_MODEMCTRL 1 +#define FTDI_COMMAND_GETMODEMSTATUS 5 /* Retrieve current value of modem status register */ +#define FTDI_COMMAND_SETEVENTCHAR 6 /* Set the event character */ +#define FTDI_COMMAND_SETERRORCHAR 7 /* Set the error character */ +#define FTDI_COMMAND_SETLATENCYTIMER 9 /* Set the latency timer */ +#define FTDI_COMMAND_GETLATENCYTIMER 10 /* Get the latency timer */ +#endif + +/* + * DATA FORMAT + * + * IN Endpoint + * + * The device reserves the first two bytes of data on this endpoint to contain + * the current values of the modem and line status registers. In the absence of + * data, the device generates a message consisting of these two status bytes + * every 40 ms + * + * Byte 0: Modem Status + * + * Offset Description + * B0 Reserved - must be 1 + * B1 Reserved - must be 0 + * B2 Reserved - must be 0 + * B3 Reserved - must be 0 + * B4 Clear to Send (CTS) + * B5 Data Set Ready (DSR) + * B6 Ring Indicator (RI) + * B7 Receive Line Signal Detect (RLSD) + * + * Byte 1: Line Status + * + * Offset Description + * B0 Data Ready (DR) + * B1 Overrun Error (OE) + * B2 Parity Error (PE) + * B3 Framing Error (FE) + * B4 Break Interrupt (BI) + * B5 Transmitter Holding Register (THRE) + * B6 Transmitter Empty (TEMT) + * B7 Error in RCVR FIFO + * + */ +#define FTDI_RS0_CTS (1 << 4) +#define FTDI_RS0_DSR (1 << 5) +#define FTDI_RS0_RI (1 << 6) +#define FTDI_RS0_RLSD (1 << 7) + +#define FTDI_RS_DR 1 +#define FTDI_RS_OE (1<<1) +#define FTDI_RS_PE (1<<2) +#define FTDI_RS_FE (1<<3) +#define FTDI_RS_BI (1<<4) +#define FTDI_RS_THRE (1<<5) +#define FTDI_RS_TEMT (1<<6) +#define FTDI_RS_FIFO (1<<7) + + +static usbh_urbstatus_t _ftdi_port_control(USBHFTDIPortDriver *ftdipp, + uint8_t bRequest, uint8_t wValue, uint8_t bHIndex, uint16_t wLength, + uint8_t *buff) { + + static const uint8_t bmRequestType[] = { + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //0 FTDI_COMMAND_RESET + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //1 FTDI_COMMAND_MODEMCTRL + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //2 FTDI_COMMAND_SETFLOW + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //3 FTDI_COMMAND_SETBAUD + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, //4 FTDI_COMMAND_SETDATA + }; + + osalDbgCheck(bRequest < sizeof_array(bmRequestType)); + osalDbgCheck(bRequest != 1); + + const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = { + bmRequestType[bRequest], + bRequest, + wValue, + (bHIndex << 8) | (ftdipp->ifnum + 1), + wLength + }; + + return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, buff, NULL, MS2ST(1000)); +} + +static uint32_t _get_divisor(uint32_t baud, usbhftdi_type_t type) { + static const uint8_t divfrac[8] = {0, 3, 2, 4, 1, 5, 6, 7}; + uint32_t divisor; + + if (type == USBHFTDI_TYPE_A) { + uint32_t divisor3 = ((48000000UL / 2) + baud / 2) / baud; + uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor3); + if ((divisor3 & 0x7) == 7) + divisor3++; /* round x.7/8 up to x+1 */ + + divisor = divisor3 >> 3; + divisor3 &= 0x7; + if (divisor3 == 1) + divisor |= 0xc000; + else if (divisor3 >= 4) + divisor |= 0x4000; + else if (divisor3 != 0) + divisor |= 0x8000; + else if (divisor == 1) + divisor = 0; /* special case for maximum baud rate */ + } else { + if (type == USBHFTDI_TYPE_B) { + divisor = ((48000000UL / 2) + baud / 2) / baud; + uinfof("FTDI: desired=%dbps, real=%dbps", baud, (48000000UL / 2) / divisor); + } else { + /* hi-speed baud rate is 10-bit sampling instead of 16-bit */ + if (baud < 1200) + baud = 1200; + divisor = (120000000UL * 8 + baud * 5) / (baud * 10); + uinfof("FTDI: desired=%dbps, real=%dbps", baud, (120000000UL * 8) / divisor / 10); + } + divisor = (divisor >> 3) | (divfrac[divisor & 0x7] << 14); + + /* Deal with special cases for highest baud rates. */ + if (divisor == 1) + divisor = 0; + else if (divisor == 0x4001) + divisor = 1; + + if (type == USBHFTDI_TYPE_H) + divisor |= 0x00020000; + } + return divisor; +} + +static usbh_urbstatus_t _set_baudrate(USBHFTDIPortDriver *ftdipp, uint32_t baudrate) { + uint32_t divisor = _get_divisor(baudrate, ftdipp->ftdip->type); + uint16_t wValue = (uint16_t)divisor; + uint16_t wIndex = (uint16_t)(divisor >> 16); + if (ftdipp->ftdip->dev->basicConfigDesc.bNumInterfaces > 1) + wIndex = (wIndex << 8) | (ftdipp->ifnum + 1); + + const USBH_DEFINE_BUFFER(usbh_control_request_t, req) = { + USBH_REQTYPE_VENDOR | USBH_REQTYPE_OUT | USBH_REQTYPE_DEVICE, + FTDI_COMMAND_SETBAUD, + wValue, + wIndex, + 0 + }; + return usbhControlRequestExtended(ftdipp->ftdip->dev, &req, NULL, NULL, MS2ST(1000)); +} + + +static void _submitOutI(USBHFTDIPortDriver *ftdipp, uint32_t len) { + udbgf("FTDI: Submit OUT %d", len); + ftdipp->oq_urb.requestedLength = len; + usbhURBObjectResetI(&ftdipp->oq_urb); + usbhURBSubmitI(&ftdipp->oq_urb); +} + +static void _out_cb(usbh_urb_t *urb) { + USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData; + switch (urb->status) { + case USBH_URBSTATUS_OK: + ftdipp->oq_ptr = ftdipp->oq_buff; + ftdipp->oq_counter = 64; + chThdDequeueNextI(&ftdipp->oq_waiting, Q_OK); + return; + case USBH_URBSTATUS_DISCONNECTED: + uwarn("FTDI: URB OUT disconnected"); + chThdDequeueNextI(&ftdipp->oq_waiting, Q_RESET); + return; + default: + uerrf("FTDI: URB OUT status unexpected = %d", urb->status); + break; + } + usbhURBObjectResetI(&ftdipp->oq_urb); + usbhURBSubmitI(&ftdipp->oq_urb); +} + +static size_t _write_timeout(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, + size_t n, systime_t timeout) { + chDbgCheck(n > 0U); + + size_t w = 0; + chSysLock(); + while (true) { + if (ftdipp->state != USBHFTDIP_STATE_READY) { + chSysUnlock(); + return w; + } + while (usbhURBIsBusy(&ftdipp->oq_urb)) { + if (chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout) != Q_OK) { + chSysUnlock(); + return w; + } + } + + *ftdipp->oq_ptr++ = *bp++; + if (--ftdipp->oq_counter == 0) { + _submitOutI(ftdipp, 64); + chSchRescheduleS(); + } + chSysUnlock(); /* Gives a preemption chance in a controlled point.*/ + + w++; + if (--n == 0U) + return w; + + chSysLock(); + } +} + +static msg_t _put_timeout(USBHFTDIPortDriver *ftdipp, uint8_t b, systime_t timeout) { + + chSysLock(); + if (ftdipp->state != USBHFTDIP_STATE_READY) { + chSysUnlock(); + return Q_RESET; + } + + while (usbhURBIsBusy(&ftdipp->oq_urb)) { + msg_t msg = chThdEnqueueTimeoutS(&ftdipp->oq_waiting, timeout); + if (msg < Q_OK) { + chSysUnlock(); + return msg; + } + } + + *ftdipp->oq_ptr++ = b; + if (--ftdipp->oq_counter == 0) { + _submitOutI(ftdipp, 64); + chSchRescheduleS(); + } + chSysUnlock(); + return Q_OK; +} + +static size_t _write(USBHFTDIPortDriver *ftdipp, const uint8_t *bp, size_t n) { + return _write_timeout(ftdipp, bp, n, TIME_INFINITE); +} + +static msg_t _put(USBHFTDIPortDriver *ftdipp, uint8_t b) { + return _put_timeout(ftdipp, b, TIME_INFINITE); +} + +static void _submitInI(USBHFTDIPortDriver *ftdipp) { + udbg("FTDI: Submit IN"); + usbhURBObjectResetI(&ftdipp->iq_urb); + usbhURBSubmitI(&ftdipp->iq_urb); +} + +static void _in_cb(usbh_urb_t *urb) { + USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)urb->userData; + switch (urb->status) { + case USBH_URBSTATUS_OK: + if (urb->actualLength < 2) { + uwarnf("FTDI: URB IN actualLength = %d, < 2", urb->actualLength); + } else if (urb->actualLength > 2) { + udbgf("FTDI: URB IN data len=%d, status=%02x %02x", + urb->actualLength - 2, + ((uint8_t *)urb->buff)[0], + ((uint8_t *)urb->buff)[1]); + ftdipp->iq_ptr = ftdipp->iq_buff + 2; + ftdipp->iq_counter = urb->actualLength - 2; + chThdDequeueNextI(&ftdipp->iq_waiting, Q_OK); + return; + } else { + udbgf("FTDI: URB IN no data, status=%02x %02x", + ((uint8_t *)urb->buff)[0], + ((uint8_t *)urb->buff)[1]); + return; + } + break; + case USBH_URBSTATUS_DISCONNECTED: + uwarn("FTDI: URB IN disconnected"); + chThdDequeueNextI(&ftdipp->iq_waiting, Q_RESET); + return; + default: + uerrf("FTDI: URB IN status unexpected = %d", urb->status); + break; + } + _submitInI(ftdipp); +} + +static size_t _read_timeout(USBHFTDIPortDriver *ftdipp, uint8_t *bp, + size_t n, systime_t timeout) { + size_t r = 0; + + chDbgCheck(n > 0U); + + chSysLock(); + while (true) { + if (ftdipp->state != USBHFTDIP_STATE_READY) { + chSysUnlock(); + return r; + } + while (ftdipp->iq_counter == 0) { + if (!usbhURBIsBusy(&ftdipp->iq_urb)) + _submitInI(ftdipp); + if (chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout) != Q_OK) { + chSysUnlock(); + return r; + } + } + *bp++ = *ftdipp->iq_ptr++; + if (--ftdipp->iq_counter == 0) { + _submitInI(ftdipp); + chSchRescheduleS(); + } + chSysUnlock(); + + r++; + if (--n == 0U) + return r; + + chSysLock(); + } +} + +static msg_t _get_timeout(USBHFTDIPortDriver *ftdipp, systime_t timeout) { + uint8_t b; + + chSysLock(); + if (ftdipp->state != USBHFTDIP_STATE_READY) { + chSysUnlock(); + return Q_RESET; + } + while (ftdipp->iq_counter == 0) { + if (!usbhURBIsBusy(&ftdipp->iq_urb)) + _submitInI(ftdipp); + msg_t msg = chThdEnqueueTimeoutS(&ftdipp->iq_waiting, timeout); + if (msg < Q_OK) { + chSysUnlock(); + return msg; + } + } + b = *ftdipp->iq_ptr++; + if (--ftdipp->iq_counter == 0) { + _submitInI(ftdipp); + chSchRescheduleS(); + } + chSysUnlock(); + + return (msg_t)b; +} + +static msg_t _get(USBHFTDIPortDriver *ftdipp) { + return _get_timeout(ftdipp, TIME_INFINITE); +} + +static size_t _read(USBHFTDIPortDriver *ftdipp, uint8_t *bp, size_t n) { + return _read_timeout(ftdipp, bp, n, TIME_INFINITE); +} + +static void _vt(void *p) { + USBHFTDIPortDriver *const ftdipp = (USBHFTDIPortDriver *)p; + chSysLockFromISR(); + uint32_t len = ftdipp->oq_ptr - ftdipp->oq_buff; + if (len && !usbhURBIsBusy(&ftdipp->oq_urb)) { + _submitOutI(ftdipp, len); + } + if ((ftdipp->iq_counter == 0) && !usbhURBIsBusy(&ftdipp->iq_urb)) { + _submitInI(ftdipp); + } + chVTSetI(&ftdipp->vt, MS2ST(16), _vt, ftdipp); + chSysUnlockFromISR(); +} + +static const struct FTDIPortDriverVMT async_channel_vmt = { + (size_t (*)(void *, const uint8_t *, size_t))_write, + (size_t (*)(void *, uint8_t *, size_t))_read, + (msg_t (*)(void *, uint8_t))_put, + (msg_t (*)(void *))_get, + (msg_t (*)(void *, uint8_t, systime_t))_put_timeout, + (msg_t (*)(void *, systime_t))_get_timeout, + (size_t (*)(void *, const uint8_t *, size_t, systime_t))_write_timeout, + (size_t (*)(void *, uint8_t *, size_t, systime_t))_read_timeout +}; + + +static void _stop(USBHFTDIPortDriver *ftdipp) { + osalSysLock(); + chVTResetI(&ftdipp->vt); + usbhEPCloseS(&ftdipp->epin); + usbhEPCloseS(&ftdipp->epout); + chThdDequeueAllI(&ftdipp->iq_waiting, Q_RESET); + chThdDequeueAllI(&ftdipp->oq_waiting, Q_RESET); + osalOsRescheduleS(); + ftdipp->state = USBHFTDIP_STATE_ACTIVE; + osalSysUnlock(); +} + +void usbhftdipStop(USBHFTDIPortDriver *ftdipp) { + osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE) + || (ftdipp->state == USBHFTDIP_STATE_READY)); + + if (ftdipp->state == USBHFTDIP_STATE_ACTIVE) { + return; + } + + osalMutexLock(&ftdipp->ftdip->mtx); + _stop(ftdipp); + osalMutexUnlock(&ftdipp->ftdip->mtx); +} + +void usbhftdipStart(USBHFTDIPortDriver *ftdipp, const USBHFTDIPortConfig *config) { + static const USBHFTDIPortConfig default_config = { + HAL_USBHFTDI_DEFAULT_SPEED, + HAL_USBHFTDI_DEFAULT_FRAMING, + HAL_USBHFTDI_DEFAULT_HANDSHAKE, + HAL_USBHFTDI_DEFAULT_XON, + HAL_USBHFTDI_DEFAULT_XOFF + }; + + osalDbgCheck((ftdipp->state == USBHFTDIP_STATE_ACTIVE) + || (ftdipp->state == USBHFTDIP_STATE_READY)); + + if (ftdipp->state == USBHFTDIP_STATE_READY) + return; + + osalMutexLock(&ftdipp->ftdip->mtx); + if (config == NULL) + config = &default_config; + + uint16_t wValue = 0; + _ftdi_port_control(ftdipp, FTDI_COMMAND_RESET, FTDI_RESET_ALL, 0, 0, NULL); + _set_baudrate(ftdipp, config->speed); + _ftdi_port_control(ftdipp, FTDI_COMMAND_SETDATA, config->framing, 0, 0, NULL); + if (config->handshake & USBHFTDI_HANDSHAKE_XON_XOFF) + wValue = (config->xoff_character << 8) | config->xon_character; + _ftdi_port_control(ftdipp, FTDI_COMMAND_SETFLOW, wValue, config->handshake, 0, NULL); + + usbhURBObjectInit(&ftdipp->oq_urb, &ftdipp->epout, _out_cb, ftdipp, ftdipp->oq_buff, 0); + chThdQueueObjectInit(&ftdipp->oq_waiting); + ftdipp->oq_counter = 64; + ftdipp->oq_ptr = ftdipp->oq_buff; + usbhEPOpen(&ftdipp->epout); + + usbhURBObjectInit(&ftdipp->iq_urb, &ftdipp->epin, _in_cb, ftdipp, ftdipp->iq_buff, 64); + chThdQueueObjectInit(&ftdipp->iq_waiting); + ftdipp->iq_counter = 0; + ftdipp->iq_ptr = ftdipp->iq_buff; + usbhEPOpen(&ftdipp->epin); + osalSysLock(); + usbhURBSubmitI(&ftdipp->iq_urb); + osalSysUnlock(); + + chVTObjectInit(&ftdipp->vt); + chVTSet(&ftdipp->vt, MS2ST(16), _vt, ftdipp); + + ftdipp->state = USBHFTDIP_STATE_READY; + osalMutexUnlock(&ftdipp->ftdip->mtx); +} + +void usbhftdiObjectInit(USBHFTDIDriver *ftdip) { + osalDbgCheck(ftdip != NULL); + memset(ftdip, 0, sizeof(*ftdip)); + ftdip->info = &usbhftdiClassDriverInfo; + osalMutexObjectInit(&ftdip->mtx); +} + +void usbhftdipObjectInit(USBHFTDIPortDriver *ftdipp) { + osalDbgCheck(ftdipp != NULL); + memset(ftdipp, 0, sizeof(*ftdipp)); + ftdipp->vmt = &async_channel_vmt; + ftdipp->state = USBHFTDIP_STATE_STOP; +} + +#endif diff --git a/os/hal/src/usbh/usbh_hub.c b/os/hal/src/usbh/hal_usbh_hub.c index eb585d2..7fdcef1 100644 --- a/os/hal/src/usbh/usbh_hub.c +++ b/os/hal/src/usbh/hal_usbh_hub.c @@ -1,302 +1,302 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-#include "usbh.h"
-#include "usbh/internal.h"
-
-#if HAL_USBH_USE_HUB
-
-#if !HAL_USE_USBH
-#error "USBHHUB needs HAL_USE_USBH"
-#endif
-
-#include <string.h>
-#include "usbh/dev/hub.h"
-
-#if USBHHUB_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBHHUB_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBHHUB_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBHHUB_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-
-USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES];
-usbh_port_t USBHPorts[HAL_USBHHUB_MAX_PORTS];
-
-static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
-static void hub_unload(usbh_baseclassdriver_t *drv);
-static const usbh_classdriver_vmt_t usbhhubClassDriverVMT = {
- hub_load,
- hub_unload
-};
-const usbh_classdriverinfo_t usbhhubClassDriverInfo = {
- 0x09, 0x00, -1, "HUB", &usbhhubClassDriverVMT
-};
-
-
-void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh,
- USBHHubDriver *hub, uint8_t number) {
- memset(port, 0, sizeof(*port));
- port->number = number;
- port->device.host = usbh;
- port->hub = hub;
-}
-
-usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host, USBHHubDriver *hub,
- uint8_t bmRequestType,
- uint8_t bRequest,
- uint16_t wValue,
- uint16_t wIndex,
- uint16_t wLength,
- uint8_t *buf) {
- if (hub == NULL)
- return usbh_lld_root_hub_request(host, bmRequestType, bRequest, wValue, wIndex, wLength, buf);
-
- return usbhControlRequest(hub->dev,
- bmRequestType, bRequest, wValue, wIndex, wLength, buf);
-}
-
-
-static void _urb_complete(usbh_urb_t *urb) {
-
- USBHHubDriver *const hubdp = (USBHHubDriver *)urb->userData;
- switch (urb->status) {
- case USBH_URBSTATUS_TIMEOUT:
- /* the device NAKed */
- udbg("HUB: no info");
- hubdp->statuschange = 0;
- break;
- case USBH_URBSTATUS_OK: {
- uint8_t len = hubdp->hubDesc.bNbrPorts / 8 + 1;
- if (urb->actualLength != len) {
- uwarnf("Expected %d status change bytes but got %d", len, urb->actualLength);
- }
-
- if (urb->actualLength < len)
- len = urb->actualLength;
-
- if (len > 4)
- len = 4;
-
- uint8_t *sc = (uint8_t *)&hubdp->statuschange;
- uint8_t *r = hubdp->scbuff;
- while (len--)
- *sc++ |= *r++;
-
- uinfof("HUB: change, %08x", hubdp->statuschange);
- } break;
- case USBH_URBSTATUS_DISCONNECTED:
- uwarn("HUB: URB disconnected, aborting poll");
- return;
- default:
- uerrf("HUB: URB status unexpected = %d", urb->status);
- break;
- }
-
- usbhURBObjectResetI(urb);
- usbhURBSubmitI(urb);
-}
-
-static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev,
- const uint8_t *descriptor, uint16_t rem) {
- int i;
-
- USBHHubDriver *hubdp;
-
- if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_DEVICE))
- return NULL;
-
- if (dev->devDesc.bDeviceProtocol != 0)
- return NULL;
-
- generic_iterator_t iep, icfg;
- if_iterator_t iif;
-
- cfg_iter_init(&icfg, dev->fullConfigurationDescriptor,
- dev->basicConfigDesc.wTotalLength);
-
- if_iter_init(&iif, &icfg);
- if (!iif.valid)
- return NULL;
- const usbh_interface_descriptor_t *const ifdesc = if_get(&iif);
- if ((ifdesc->bInterfaceClass != 0x09)
- || (ifdesc->bInterfaceSubClass != 0x00)
- || (ifdesc->bInterfaceProtocol != 0x00)) {
- return NULL;
- }
-
- ep_iter_init(&iep, &iif);
- if (!iep.valid)
- return NULL;
- const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
- if ((epdesc->bmAttributes & 0x03) != USBH_EPTYPE_INT) {
- return NULL;
- }
-
-
- /* alloc driver */
- for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) {
- if (USBHHUBD[i].dev == NULL) {
- hubdp = &USBHHUBD[i];
- goto alloc_ok;
- }
- }
-
- uwarn("Can't alloc HUB driver");
-
- /* can't alloc */
- return NULL;
-
-alloc_ok:
- /* initialize the driver's variables */
- hubdp->epint.status = USBH_EPSTATUS_UNINITIALIZED;
- hubdp->dev = dev;
- hubdp->ports = 0;
-
- usbhEPSetName(&dev->ctrl, "HUB[CTRL]");
-
- /* read Hub descriptor */
- uinfo("Read Hub descriptor");
- if (usbhhubControlRequest(dev->host, hubdp,
- USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE,
- USBH_REQ_GET_DESCRIPTOR,
- (USBH_DT_HUB << 8), 0, sizeof(hubdp->hubDesc),
- (uint8_t *)&hubdp->hubDesc) != USBH_URBSTATUS_OK) {
- hubdp->dev = NULL;
- return NULL;
- }
-
- const usbh_hub_descriptor_t *const hubdesc = &hubdp->hubDesc;
-
- uinfof("Hub descriptor loaded; %d ports, wHubCharacteristics=%04x, bPwrOn2PwrGood=%d, bHubContrCurrent=%d",
- hubdesc->bNbrPorts,
- hubdesc->wHubCharacteristics,
- hubdesc->bPwrOn2PwrGood,
- hubdesc->bHubContrCurrent);
-
- /* Alloc ports */
- uint8_t ports = hubdesc->bNbrPorts;
- for (i = 0; (ports > 0) && (i < HAL_USBHHUB_MAX_PORTS); i++) {
- if (USBHPorts[i].hub == NULL) {
- uinfof("Alloc port %d", ports);
- _usbhub_port_object_init(&USBHPorts[i], dev->host, hubdp, ports);
- USBHPorts[i].next = hubdp->ports;
- hubdp->ports = &USBHPorts[i];
- --ports;
- }
- }
-
- if (ports) {
- uwarn("Could not alloc all ports");
- }
-
- /* link hub to the host's list */
- list_add_tail(&hubdp->node, &dev->host->hubs);
-
- /* enable power to ports */
- usbh_port_t *port = hubdp->ports;
- while (port) {
- uinfof("Enable power for port %d", port->number);
- usbhhubSetFeaturePort(port, USBH_PORT_FEAT_POWER);
- port = port->next;
- }
-
- if (hubdesc->bPwrOn2PwrGood)
- osalThreadSleepMilliseconds(2 * hubdesc->bPwrOn2PwrGood);
-
- /* initialize the status change endpoint and trigger the first transfer */
- usbhEPObjectInit(&hubdp->epint, dev, epdesc);
- usbhEPSetName(&hubdp->epint, "HUB[INT ]");
- usbhEPOpen(&hubdp->epint);
-
- usbhURBObjectInit(&hubdp->urb, &hubdp->epint,
- _urb_complete, hubdp, hubdp->scbuff,
- (hubdesc->bNbrPorts + 8) / 8);
-
- osalSysLock();
- usbhURBSubmitI(&hubdp->urb);
- osalOsRescheduleS();
- osalSysUnlock();
-
- return (usbh_baseclassdriver_t *)hubdp;
-}
-
-static void hub_unload(usbh_baseclassdriver_t *drv) {
- osalDbgCheck(drv != NULL);
- USBHHubDriver *const hubdp = (USBHHubDriver *)drv;
-
- /* close the status change endpoint (this cancels ongoing URBs) */
- osalSysLock();
- usbhEPCloseS(&hubdp->epint);
- osalSysUnlock();
-
- /* de-alloc ports and unload drivers */
- usbh_port_t *port = hubdp->ports;
- while (port) {
- _usbh_port_disconnected(port);
- port->hub = NULL;
- port = port->next;
- }
-
- /* unlink the hub from the host's list */
- list_del(&hubdp->node);
-
-}
-
-void usbhhubObjectInit(USBHHubDriver *hubdp) {
- osalDbgCheck(hubdp != NULL);
- memset(hubdp, 0, sizeof(*hubdp));
- hubdp->info = &usbhhubClassDriverInfo;
-}
-#else
-
-#if HAL_USE_USBH
-void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, uint8_t number) {
- memset(port, 0, sizeof(*port));
- port->number = number;
- port->device.host = usbh;
-}
-#endif
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "hal_usbh.h" +#include "usbh/internal.h" + +#if HAL_USBH_USE_HUB + +#if !HAL_USE_USBH +#error "USBHHUB needs HAL_USE_USBH" +#endif + +#include <string.h> +#include "usbh/dev/hub.h" + +#if USBHHUB_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBHHUB_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBHHUB_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBHHUB_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + + +USBHHubDriver USBHHUBD[HAL_USBHHUB_MAX_INSTANCES]; +usbh_port_t USBHPorts[HAL_USBHHUB_MAX_PORTS]; + +static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); +static void hub_unload(usbh_baseclassdriver_t *drv); +static const usbh_classdriver_vmt_t usbhhubClassDriverVMT = { + hub_load, + hub_unload +}; +const usbh_classdriverinfo_t usbhhubClassDriverInfo = { + 0x09, 0x00, -1, "HUB", &usbhhubClassDriverVMT +}; + + +void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, + USBHHubDriver *hub, uint8_t number) { + memset(port, 0, sizeof(*port)); + port->number = number; + port->device.host = usbh; + port->hub = hub; +} + +usbh_urbstatus_t usbhhubControlRequest(USBHDriver *host, USBHHubDriver *hub, + uint8_t bmRequestType, + uint8_t bRequest, + uint16_t wValue, + uint16_t wIndex, + uint16_t wLength, + uint8_t *buf) { + if (hub == NULL) + return usbh_lld_root_hub_request(host, bmRequestType, bRequest, wValue, wIndex, wLength, buf); + + return usbhControlRequest(hub->dev, + bmRequestType, bRequest, wValue, wIndex, wLength, buf); +} + + +static void _urb_complete(usbh_urb_t *urb) { + + USBHHubDriver *const hubdp = (USBHHubDriver *)urb->userData; + switch (urb->status) { + case USBH_URBSTATUS_TIMEOUT: + /* the device NAKed */ + udbg("HUB: no info"); + hubdp->statuschange = 0; + break; + case USBH_URBSTATUS_OK: { + uint8_t len = hubdp->hubDesc.bNbrPorts / 8 + 1; + if (urb->actualLength != len) { + uwarnf("Expected %d status change bytes but got %d", len, urb->actualLength); + } + + if (urb->actualLength < len) + len = urb->actualLength; + + if (len > 4) + len = 4; + + uint8_t *sc = (uint8_t *)&hubdp->statuschange; + uint8_t *r = hubdp->scbuff; + while (len--) + *sc++ |= *r++; + + uinfof("HUB: change, %08x", hubdp->statuschange); + } break; + case USBH_URBSTATUS_DISCONNECTED: + uwarn("HUB: URB disconnected, aborting poll"); + return; + default: + uerrf("HUB: URB status unexpected = %d", urb->status); + break; + } + + usbhURBObjectResetI(urb); + usbhURBSubmitI(urb); +} + +static usbh_baseclassdriver_t *hub_load(usbh_device_t *dev, + const uint8_t *descriptor, uint16_t rem) { + int i; + + USBHHubDriver *hubdp; + + if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_DEVICE)) + return NULL; + + if (dev->devDesc.bDeviceProtocol != 0) + return NULL; + + generic_iterator_t iep, icfg; + if_iterator_t iif; + + cfg_iter_init(&icfg, dev->fullConfigurationDescriptor, + dev->basicConfigDesc.wTotalLength); + + if_iter_init(&iif, &icfg); + if (!iif.valid) + return NULL; + const usbh_interface_descriptor_t *const ifdesc = if_get(&iif); + if ((ifdesc->bInterfaceClass != 0x09) + || (ifdesc->bInterfaceSubClass != 0x00) + || (ifdesc->bInterfaceProtocol != 0x00)) { + return NULL; + } + + ep_iter_init(&iep, &iif); + if (!iep.valid) + return NULL; + const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep); + if ((epdesc->bmAttributes & 0x03) != USBH_EPTYPE_INT) { + return NULL; + } + + + /* alloc driver */ + for (i = 0; i < HAL_USBHHUB_MAX_INSTANCES; i++) { + if (USBHHUBD[i].dev == NULL) { + hubdp = &USBHHUBD[i]; + goto alloc_ok; + } + } + + uwarn("Can't alloc HUB driver"); + + /* can't alloc */ + return NULL; + +alloc_ok: + /* initialize the driver's variables */ + hubdp->epint.status = USBH_EPSTATUS_UNINITIALIZED; + hubdp->dev = dev; + hubdp->ports = 0; + + usbhEPSetName(&dev->ctrl, "HUB[CTRL]"); + + /* read Hub descriptor */ + uinfo("Read Hub descriptor"); + if (usbhhubControlRequest(dev->host, hubdp, + USBH_REQTYPE_IN | USBH_REQTYPE_CLASS | USBH_REQTYPE_DEVICE, + USBH_REQ_GET_DESCRIPTOR, + (USBH_DT_HUB << 8), 0, sizeof(hubdp->hubDesc), + (uint8_t *)&hubdp->hubDesc) != USBH_URBSTATUS_OK) { + hubdp->dev = NULL; + return NULL; + } + + const usbh_hub_descriptor_t *const hubdesc = &hubdp->hubDesc; + + uinfof("Hub descriptor loaded; %d ports, wHubCharacteristics=%04x, bPwrOn2PwrGood=%d, bHubContrCurrent=%d", + hubdesc->bNbrPorts, + hubdesc->wHubCharacteristics, + hubdesc->bPwrOn2PwrGood, + hubdesc->bHubContrCurrent); + + /* Alloc ports */ + uint8_t ports = hubdesc->bNbrPorts; + for (i = 0; (ports > 0) && (i < HAL_USBHHUB_MAX_PORTS); i++) { + if (USBHPorts[i].hub == NULL) { + uinfof("Alloc port %d", ports); + _usbhub_port_object_init(&USBHPorts[i], dev->host, hubdp, ports); + USBHPorts[i].next = hubdp->ports; + hubdp->ports = &USBHPorts[i]; + --ports; + } + } + + if (ports) { + uwarn("Could not alloc all ports"); + } + + /* link hub to the host's list */ + list_add_tail(&hubdp->node, &dev->host->hubs); + + /* enable power to ports */ + usbh_port_t *port = hubdp->ports; + while (port) { + uinfof("Enable power for port %d", port->number); + usbhhubSetFeaturePort(port, USBH_PORT_FEAT_POWER); + port = port->next; + } + + if (hubdesc->bPwrOn2PwrGood) + osalThreadSleepMilliseconds(2 * hubdesc->bPwrOn2PwrGood); + + /* initialize the status change endpoint and trigger the first transfer */ + usbhEPObjectInit(&hubdp->epint, dev, epdesc); + usbhEPSetName(&hubdp->epint, "HUB[INT ]"); + usbhEPOpen(&hubdp->epint); + + usbhURBObjectInit(&hubdp->urb, &hubdp->epint, + _urb_complete, hubdp, hubdp->scbuff, + (hubdesc->bNbrPorts + 8) / 8); + + osalSysLock(); + usbhURBSubmitI(&hubdp->urb); + osalOsRescheduleS(); + osalSysUnlock(); + + return (usbh_baseclassdriver_t *)hubdp; +} + +static void hub_unload(usbh_baseclassdriver_t *drv) { + osalDbgCheck(drv != NULL); + USBHHubDriver *const hubdp = (USBHHubDriver *)drv; + + /* close the status change endpoint (this cancels ongoing URBs) */ + osalSysLock(); + usbhEPCloseS(&hubdp->epint); + osalSysUnlock(); + + /* de-alloc ports and unload drivers */ + usbh_port_t *port = hubdp->ports; + while (port) { + _usbh_port_disconnected(port); + port->hub = NULL; + port = port->next; + } + + /* unlink the hub from the host's list */ + list_del(&hubdp->node); + +} + +void usbhhubObjectInit(USBHHubDriver *hubdp) { + osalDbgCheck(hubdp != NULL); + memset(hubdp, 0, sizeof(*hubdp)); + hubdp->info = &usbhhubClassDriverInfo; +} +#else + +#if HAL_USE_USBH +void _usbhub_port_object_init(usbh_port_t *port, USBHDriver *usbh, uint8_t number) { + memset(port, 0, sizeof(*port)); + port->number = number; + port->device.host = usbh; +} +#endif + +#endif diff --git a/os/hal/src/usbh/usbh_msd.c b/os/hal/src/usbh/hal_usbh_msd.c index 8db68a4..6869a74 100644 --- a/os/hal/src/usbh/usbh_msd.c +++ b/os/hal/src/usbh/hal_usbh_msd.c @@ -1,939 +1,939 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-#include "usbh.h"
-
-#if HAL_USBH_USE_MSD
-
-#if !HAL_USE_USBH
-#error "USBHMSD needs USBH"
-#endif
-
-#include <string.h>
-#include "usbh/dev/msd.h"
-#include "usbh/internal.h"
-
-//#pragma GCC optimize("Og")
-
-
-#if USBHMSD_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBHMSD_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBHMSD_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBHMSD_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-
-
-
-
-/*===========================================================================*/
-/* USB Class driver loader for MSD */
-/*===========================================================================*/
-
-USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES];
-
-static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem);
-static void _msd_unload(usbh_baseclassdriver_t *drv);
-
-static const usbh_classdriver_vmt_t class_driver_vmt = {
- _msd_load,
- _msd_unload
-};
-
-const usbh_classdriverinfo_t usbhmsdClassDriverInfo = {
- 0x08, 0x06, 0x50, "MSD", &class_driver_vmt
-};
-
-#define MSD_REQ_RESET 0xFF
-#define MSD_GET_MAX_LUN 0xFE
-
-static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
- int i;
- USBHMassStorageDriver *msdp;
- uint8_t luns; // should declare it here to eliminate 'control bypass initialization' warning
- usbh_urbstatus_t stat; // should declare it here to eliminate 'control bypass initialization' warning
-
- if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE))
- return NULL;
-
- const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor;
-
- if ((ifdesc->bAlternateSetting != 0)
- || (ifdesc->bNumEndpoints < 2)
- || (ifdesc->bInterfaceSubClass != 0x06)
- || (ifdesc->bInterfaceProtocol != 0x50)) {
- return NULL;
- }
-
- /* alloc driver */
- for (i = 0; i < HAL_USBHMSD_MAX_INSTANCES; i++) {
- if (USBHMSD[i].dev == NULL) {
- msdp = &USBHMSD[i];
- goto alloc_ok;
- }
- }
-
- uwarn("Can't alloc MSD driver");
-
- /* can't alloc */
- return NULL;
-
-alloc_ok:
- /* initialize the driver's variables */
- msdp->epin.status = USBH_EPSTATUS_UNINITIALIZED;
- msdp->epout.status = USBH_EPSTATUS_UNINITIALIZED;
- msdp->max_lun = 0;
- msdp->tag = 0;
- msdp->luns = 0;
- msdp->ifnum = ifdesc->bInterfaceNumber;
- usbhEPSetName(&dev->ctrl, "MSD[CTRL]");
-
- /* parse the configuration descriptor */
- if_iterator_t iif;
- generic_iterator_t iep;
- iif.iad = 0;
- iif.curr = descriptor;
- iif.rem = rem;
- for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) {
- const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep);
- if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
- uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
- usbhEPObjectInit(&msdp->epin, dev, epdesc);
- usbhEPSetName(&msdp->epin, "MSD[BIN ]");
- } else if (((epdesc->bEndpointAddress & 0x80) == 0)
- && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) {
- uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress);
- usbhEPObjectInit(&msdp->epout, dev, epdesc);
- usbhEPSetName(&msdp->epout, "MSD[BOUT]");
- } else {
- uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x",
- epdesc->bEndpointAddress, epdesc->bmAttributes);
- }
- }
- if ((msdp->epin.status != USBH_EPSTATUS_CLOSED) || (msdp->epout.status != USBH_EPSTATUS_CLOSED)) {
- goto deinit;
- }
-
- /* read the number of LUNs */
- uinfo("Reading Max LUN:");
- USBH_DEFINE_BUFFER(uint8_t, buff[4]);
- stat = usbhControlRequest(dev,
- USBH_CLASSIN(USBH_REQTYPE_INTERFACE, MSD_GET_MAX_LUN, 0, msdp->ifnum),
- 1, buff);
- if (stat == USBH_URBSTATUS_OK) {
- msdp->max_lun = buff[0] + 1;
- uinfof("\tmax_lun = %d", msdp->max_lun);
- if (msdp->max_lun > HAL_USBHMSD_MAX_LUNS) {
- msdp->max_lun = HAL_USBHMSD_MAX_LUNS;
- uwarnf("\tUsing max_lun = %d", msdp->max_lun);
- }
- } else if (stat == USBH_URBSTATUS_STALL) {
- uwarn("\tStall, max_lun = 1");
- msdp->max_lun = 1;
- } else {
- uerr("\tError");
- goto deinit;
- }
-
- /* open the bulk IN/OUT endpoints */
- usbhEPOpen(&msdp->epin);
- usbhEPOpen(&msdp->epout);
-
- /* Alloc one block device per logical unit found */
- luns = msdp->max_lun;
- for (i = 0; (luns > 0) && (i < HAL_USBHMSD_MAX_LUNS); i++) {
- if (MSBLKD[i].msdp == NULL) {
- /* link the new block driver to the list */
- MSBLKD[i].next = msdp->luns;
- msdp->luns = &MSBLKD[i];
- MSBLKD[i].msdp = msdp;
-
- osalSysLock();
- MSBLKD[i].state = BLK_ACTIVE; /* transition directly to active, instead of BLK_STOP */
- osalSysUnlock();
-
- /* connect the LUN (TODO: review if it's best to leave the LUN disconnected) */
- usbhmsdLUNConnect(&MSBLKD[i]);
- luns--;
- }
- }
-
- return (usbh_baseclassdriver_t *)msdp;
-
-deinit:
- /* Here, the enpoints are closed, and the driver is unlinked */
- return NULL;
-}
-
-static void _msd_unload(usbh_baseclassdriver_t *drv) {
- osalDbgCheck(drv != NULL);
- USBHMassStorageDriver *const msdp = (USBHMassStorageDriver *)drv;
- USBHMassStorageLUNDriver *lunp = msdp->luns;
-
- osalMutexLock(&msdp->mtx);
- osalSysLock();
- usbhEPCloseS(&msdp->epin);
- usbhEPCloseS(&msdp->epout);
- while (lunp) {
- lunp->state = BLK_STOP;
- lunp = lunp->next;
- }
- osalSysUnlock();
- osalMutexUnlock(&msdp->mtx);
-
- /* now that the LUNs are idle, deinit them */
- lunp = msdp->luns;
- osalSysLock();
- while (lunp) {
- usbhmsdLUNObjectInit(lunp);
- lunp = lunp->next;
- }
- osalSysUnlock();
-}
-
-
-/*===========================================================================*/
-/* MSD Class driver operations (Bulk-Only transport) */
-/*===========================================================================*/
-
-
-
-/* USB Bulk Only Transport SCSI Command block wrapper */
-PACKED_STRUCT {
- uint32_t dCBWSignature;
- uint32_t dCBWTag;
- uint32_t dCBWDataTransferLength;
- uint8_t bmCBWFlags;
- uint8_t bCBWLUN;
- uint8_t bCBWCBLength;
- uint8_t CBWCB[16];
-} msd_cbw_t;
-#define MSD_CBW_SIGNATURE 0x43425355
-#define MSD_CBWFLAGS_D2H 0x80
-#define MSD_CBWFLAGS_H2D 0x00
-
-
-/* USB Bulk Only Transport SCSI Command status wrapper */
-PACKED_STRUCT {
- uint32_t dCSWSignature;
- uint32_t dCSWTag;
- uint32_t dCSWDataResidue;
- uint8_t bCSWStatus;
-} msd_csw_t;
-#define MSD_CSW_SIGNATURE 0x53425355
-
-
-typedef union {
- msd_cbw_t cbw;
- msd_csw_t csw;
-} msd_transaction_t;
-
-typedef enum {
- MSD_TRANSACTIONRESULT_OK,
- MSD_TRANSACTIONRESULT_DISCONNECTED,
- MSD_TRANSACTIONRESULT_STALL,
- MSD_TRANSACTIONRESULT_BUS_ERROR,
- MSD_TRANSACTIONRESULT_SYNC_ERROR
-} msd_transaction_result_t;
-
-typedef enum {
- MSD_COMMANDRESULT_PASSED = 0,
- MSD_COMMANDRESULT_FAILED = 1,
- MSD_COMMANDRESULT_PHASE_ERROR = 2
-} msd_command_result_t;
-
-typedef struct {
- msd_transaction_result_t tres;
- msd_command_result_t cres;
-} msd_result_t;
-
-
-/* ----------------------------------------------------- */
-/* SCSI Commands */
-/* ----------------------------------------------------- */
-
-/* Read 10 and Write 10 */
-#define SCSI_CMD_READ_10 0x28
-#define SCSI_CMD_WRITE_10 0x2A
-
-/* Request sense */
-#define SCSI_CMD_REQUEST_SENSE 0x03
-PACKED_STRUCT {
- uint8_t byte[18];
-} scsi_sense_response_t;
-
-#define SCSI_SENSE_KEY_GOOD 0x00
-#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01
-#define SCSI_SENSE_KEY_NOT_READY 0x02
-#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03
-#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04
-#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05
-#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06
-#define SCSI_SENSE_KEY_DATA_PROTECT 0x07
-#define SCSI_SENSE_KEY_BLANK_CHECK 0x08
-#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09
-#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A
-#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B
-#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D
-#define SCSI_SENSE_KEY_MISCOMPARE 0x0E
-#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00
-#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04
-#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24
-#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28
-#define SCSI_ASENSE_WRITE_PROTECTED 0x27
-#define SCSI_ASENSE_FORMAT_ERROR 0x31
-#define SCSI_ASENSE_INVALID_COMMAND 0x20
-#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21
-#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A
-#define SCSI_ASENSEQ_NO_QUALIFIER 0x00
-#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01
-#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02
-#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07
-
-/* Inquiry */
-#define SCSI_CMD_INQUIRY 0x12
-PACKED_STRUCT {
- uint8_t peripheral;
- uint8_t removable;
- uint8_t version;
- uint8_t response_data_format;
- uint8_t additional_length;
- uint8_t sccstp;
- uint8_t bqueetc;
- uint8_t cmdque;
- uint8_t vendorID[8];
- uint8_t productID[16];
- uint8_t productRev[4];
-} scsi_inquiry_response_t;
-
-/* Read Capacity 10 */
-#define SCSI_CMD_READ_CAPACITY_10 0x25
-PACKED_STRUCT {
- uint32_t last_block_addr;
- uint32_t block_size;
-} scsi_readcapacity10_response_t;
-
-/* Start/Stop Unit */
-#define SCSI_CMD_START_STOP_UNIT 0x1B
-PACKED_STRUCT {
- uint8_t op_code;
- uint8_t lun_immed;
- uint8_t res1;
- uint8_t res2;
- uint8_t loej_start;
- uint8_t control;
-} scsi_startstopunit_request_t;
-
-/* test unit ready */
-#define SCSI_CMD_TEST_UNIT_READY 0x00
-
-/* Other commands, TODO: use or remove them
-#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
-#define SCSI_CMD_VERIFY_10 0x2F
-#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
-#define SCSI_CMD_MODE_SENSE_6 0x1A
-*/
-
-static inline void _prepare_cbw(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp) {
- tran->cbw.bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]);
- memset(&tran->cbw.CBWCB, 0, sizeof(tran->cbw.CBWCB));
-}
-
-static msd_transaction_result_t _msd_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) {
-
- uint32_t actual_len;
- usbh_urbstatus_t status;
-
- tran->cbw.dCBWSignature = MSD_CBW_SIGNATURE;
- tran->cbw.dCBWTag = ++lunp->msdp->tag;
-
- /* control phase */
- status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw,
- sizeof(tran->cbw), &actual_len, MS2ST(1000));
-
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Control phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Control phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != sizeof(tran->cbw)) {
- uerrf("\tMSD: Control phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- }
-
-
- /* data phase */
- if (tran->cbw.dCBWDataTransferLength) {
- status = usbhBulkTransfer(
- tran->cbw.bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout,
- data,
- tran->cbw.dCBWDataTransferLength,
- &actual_len, MS2ST(20000));
-
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Data phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Data phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != tran->cbw.dCBWDataTransferLength) {
- uerrf("\tMSD: Data phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- }
- }
-
-
- /* status phase */
- status = usbhBulkTransfer(&lunp->msdp->epin, &tran->csw,
- sizeof(tran->csw), &actual_len, MS2ST(1000));
-
- if (status == USBH_URBSTATUS_CANCELLED) {
- uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED");
- return MSD_TRANSACTIONRESULT_DISCONNECTED;
- } else if (status == USBH_URBSTATUS_STALL) {
- uerr("\tMSD: Status phase: USBH_URBSTATUS_STALL");
- return MSD_TRANSACTIONRESULT_STALL;
- } else if (status != USBH_URBSTATUS_OK) {
- uerrf("\tMSD: Status phase: status = %d, != OK", status);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (actual_len != sizeof(tran->csw)) {
- uerrf("\tMSD: Status phase: wrong actual_len = %d", actual_len);
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (tran->csw.dCSWSignature != MSD_CSW_SIGNATURE) {
- uerr("\tMSD: Status phase: wrong signature");
- return MSD_TRANSACTIONRESULT_BUS_ERROR;
- } else if (tran->csw.dCSWTag != lunp->msdp->tag) {
- uerrf("\tMSD: Status phase: wrong tag (expected %d, got %d)",
- lunp->msdp->tag, tran->csw.dCSWTag);
- return MSD_TRANSACTIONRESULT_SYNC_ERROR;
- }
-
- if (tran->csw.dCSWDataResidue) {
- uwarnf("\tMSD: Residue=%d", tran->csw.dCSWDataResidue);
- }
-
- return MSD_TRANSACTIONRESULT_OK;
-}
-
-
-static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 6;
- transaction.cbw.CBWCB[0] = SCSI_CMD_INQUIRY;
- transaction.cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t);
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 12;
- transaction.cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE;
- transaction.cbw.CBWCB[4] = sizeof(scsi_sense_response_t);
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = 0;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 6;
- transaction.cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY;
-
- res.tres = _msd_transaction(&transaction, lunp, NULL);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t);
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 12;
- transaction.cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10;
-
- res.tres = _msd_transaction(&transaction, lunp, resp);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-
-static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H;
- transaction.cbw.bCBWCBLength = 10;
- transaction.cbw.CBWCB[0] = SCSI_CMD_READ_10;
- transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
- transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
- transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
- transaction.cbw.CBWCB[5] = (uint8_t)(lba);
- transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
- transaction.cbw.CBWCB[8] = (uint8_t)(n);
-
- res.tres = _msd_transaction(&transaction, lunp, data);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data) {
- msd_transaction_t transaction;
- msd_result_t res;
-
- _prepare_cbw(&transaction, lunp);
- transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size;
- transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_H2D;
- transaction.cbw.bCBWCBLength = 10;
- transaction.cbw.CBWCB[0] = SCSI_CMD_WRITE_10;
- transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24);
- transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16);
- transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8);
- transaction.cbw.CBWCB[5] = (uint8_t)(lba);
- transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8);
- transaction.cbw.CBWCB[8] = (uint8_t)(n);
-
- res.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data);
- if (res.tres == MSD_TRANSACTIONRESULT_OK) {
- res.cres = (msd_command_result_t) transaction.csw.bCSWStatus;
- }
- return res;
-}
-
-
-
-/*===========================================================================*/
-/* Block driver data/functions */
-/*===========================================================================*/
-
-USBHMassStorageLUNDriver MSBLKD[HAL_USBHMSD_MAX_LUNS];
-
-static const struct USBHMassStorageDriverVMT blk_vmt = {
- (bool (*)(void *))usbhmsdLUNIsInserted,
- (bool (*)(void *))usbhmsdLUNIsProtected,
- (bool (*)(void *))usbhmsdLUNConnect,
- (bool (*)(void *))usbhmsdLUNDisconnect,
- (bool (*)(void *, uint32_t, uint8_t *, uint32_t))usbhmsdLUNRead,
- (bool (*)(void *, uint32_t, const uint8_t *, uint32_t))usbhmsdLUNWrite,
- (bool (*)(void *))usbhmsdLUNSync,
- (bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo
-};
-
-
-
-static uint32_t _requestsense(USBHMassStorageLUNDriver *lunp) {
- scsi_sense_response_t sense;
- msd_result_t res;
-
- res = scsi_requestsense(lunp, &sense);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREQUEST SENSE: Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tREQUEST SENSE: Command Failed");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREQUEST SENSE: Command Phase Error");
- goto failed;
- }
-
- uerrf("\tREQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x",
- sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]);
-
- return (sense.byte[2] & 0xf) | (sense.byte[12] << 8) | (sense.byte[13] << 16);
-
-failed:
- return 0xffffffff;
-}
-
-void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- memset(lunp, 0, sizeof(*lunp));
- lunp->vmt = &blk_vmt;
- lunp->state = BLK_STOP;
- /* Unnecessary because of the memset:
- lunp->msdp = NULL;
- lunp->next = NULL;
- lunp->info.* = 0;
- */
-}
-
-void usbhmsdLUNStart(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- osalSysLock();
- osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE),
- "invalid state");
- //TODO: complete
- //lunp->state = BLK_ACTIVE;
- osalSysUnlock();
-}
-
-void usbhmsdLUNStop(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- osalSysLock();
- osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE),
- "invalid state");
- //TODO: complete
- //lunp->state = BLK_STOP;
- osalSysUnlock();
-}
-
-bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) {
- USBHMassStorageDriver *const msdp = lunp->msdp;
- msd_result_t res;
-
- osalDbgCheck(msdp != NULL);
- osalSysLock();
- //osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY),
- // "invalid state");
- if (lunp->state == BLK_READY) {
- osalSysUnlock();
- return HAL_SUCCESS;
- } else if (lunp->state != BLK_ACTIVE) {
- osalSysUnlock();
- return HAL_FAILED;
- }
- lunp->state = BLK_CONNECTING;
- osalSysUnlock();
-
- osalMutexLock(&msdp->mtx);
-
- USBH_DEFINE_BUFFER(union {
- scsi_inquiry_response_t inq;
- scsi_readcapacity10_response_t cap; }, u);
-
- uinfo("INQUIRY...");
- res = scsi_inquiry(lunp, &u.inq);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tINQUIRY: Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tINQUIRY: Command Failed");
- _requestsense(lunp);
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tINQUIRY: Command Phase Error");
- goto failed;
- }
-
- uinfof("\tPDT=%02x", u.inq.peripheral & 0x1f);
- if (u.inq.peripheral != 0) {
- uerr("\tUnsupported PDT");
- goto failed;
- }
-
- // Test if unit ready
- uint8_t i;
- for (i = 0; i < 10; i++) {
- uinfo("TEST UNIT READY...");
- res = scsi_testunitready(lunp);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tTEST UNIT READY: Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tTEST UNIT READY: Command Failed");
- _requestsense(lunp);
- continue;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tTEST UNIT READY: Command Phase Error");
- goto failed;
- }
- uinfo("\tReady.");
- break;
- // osalThreadSleepMilliseconds(200); // will raise 'code is unreachable' warning
- }
- if (i == 10) goto failed;
-
- // Read capacity
- uinfo("READ CAPACITY(10)...");
- res = scsi_readcapacity10(lunp, &u.cap);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREAD CAPACITY(10): Transaction error");
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- uerr("\tREAD CAPACITY(10): Command Failed");
- _requestsense(lunp);
- goto failed;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREAD CAPACITY(10): Command Phase Error");
- goto failed;
- }
- lunp->info.blk_size = __REV(u.cap.block_size);
- lunp->info.blk_num = __REV(u.cap.last_block_addr) + 1;
- uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num,
- (uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL)));
-
- uinfo("MSD Connected.");
-
- osalMutexUnlock(&msdp->mtx);
- osalSysLock();
- lunp->state = BLK_READY;
- osalSysUnlock();
-
- return HAL_SUCCESS;
-
- /* Connection failed, state reset to BLK_ACTIVE.*/
-failed:
- osalMutexUnlock(&msdp->mtx);
- osalSysLock();
- lunp->state = BLK_ACTIVE;
- osalSysUnlock();
- return HAL_FAILED;
-}
-
-
-bool usbhmsdLUNDisconnect(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- osalSysLock();
- osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY),
- "invalid state");
- if (lunp->state == BLK_ACTIVE) {
- osalSysUnlock();
- return HAL_SUCCESS;
- }
- lunp->state = BLK_DISCONNECTING;
- osalSysUnlock();
-
- //TODO: complete
-
- osalSysLock();
- lunp->state = BLK_ACTIVE;
- osalSysUnlock();
- return HAL_SUCCESS;
-}
-
-bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
- uint8_t *buffer, uint32_t n) {
-
- osalDbgCheck(lunp != NULL);
- bool ret = HAL_FAILED;
- uint16_t blocks;
- msd_result_t res;
-
- osalSysLock();
- if (lunp->state != BLK_READY) {
- osalSysUnlock();
- return ret;
- }
- lunp->state = BLK_READING;
- osalSysUnlock();
-
- osalMutexLock(&lunp->msdp->mtx);
- while (n) {
- if (n > 0xffff) {
- blocks = 0xffff;
- } else {
- blocks = (uint16_t)n;
- }
- res = scsi_read10(lunp, startblk, blocks, buffer);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tREAD (10): Transaction error");
- goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- //TODO: request sense, and act appropriately
- uerr("\tREAD (10): Command Failed");
- _requestsense(lunp);
- goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tREAD (10): Command Phase Error");
- goto exit;
- }
- n -= blocks;
- startblk += blocks;
- buffer += blocks * lunp->info.blk_size;
- }
-
- ret = HAL_SUCCESS;
-
-exit:
- osalMutexUnlock(&lunp->msdp->mtx);
- osalSysLock();
- if (lunp->state == BLK_READING) {
- lunp->state = BLK_READY;
- } else {
- osalDbgCheck(lunp->state == BLK_STOP);
- uwarn("MSD: State = BLK_STOP");
- }
- osalSysUnlock();
- return ret;
-}
-
-bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk,
- const uint8_t *buffer, uint32_t n) {
-
- osalDbgCheck(lunp != NULL);
- bool ret = HAL_FAILED;
- uint16_t blocks;
- msd_result_t res;
-
- osalSysLock();
- if (lunp->state != BLK_READY) {
- osalSysUnlock();
- return ret;
- }
- lunp->state = BLK_WRITING;
- osalSysUnlock();
-
- osalMutexLock(&lunp->msdp->mtx);
- while (n) {
- if (n > 0xffff) {
- blocks = 0xffff;
- } else {
- blocks = (uint16_t)n;
- }
- res = scsi_write10(lunp, startblk, blocks, buffer);
- if (res.tres != MSD_TRANSACTIONRESULT_OK) {
- uerr("\tWRITE (10): Transaction error");
- goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_FAILED) {
- //TODO: request sense, and act appropriately
- uerr("\tWRITE (10): Command Failed");
- _requestsense(lunp);
- goto exit;
- } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) {
- //TODO: Do reset, etc.
- uerr("\tWRITE (10): Command Phase Error");
- goto exit;
- }
- n -= blocks;
- startblk += blocks;
- buffer += blocks * lunp->info.blk_size;
- }
-
- ret = HAL_SUCCESS;
-
-exit:
- osalMutexUnlock(&lunp->msdp->mtx);
- osalSysLock();
- if (lunp->state == BLK_WRITING) {
- lunp->state = BLK_READY;
- } else {
- osalDbgCheck(lunp->state == BLK_STOP);
- uwarn("MSD: State = BLK_STOP");
- }
- osalSysUnlock();
- return ret;
-}
-
-bool usbhmsdLUNSync(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- (void)lunp;
- //TODO: Do SCSI Sync
- return HAL_SUCCESS;
-}
-
-bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip) {
- osalDbgCheck(lunp != NULL);
- osalDbgCheck(bdip != NULL);
- *bdip = lunp->info;
- return HAL_SUCCESS;
-}
-
-bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- blkstate_t state;
- osalSysLock();
- state = lunp->state;
- osalSysUnlock();
- return (state >= BLK_ACTIVE);
-}
-
-bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp) {
- osalDbgCheck(lunp != NULL);
- return FALSE;
-}
-
-void usbhmsdObjectInit(USBHMassStorageDriver *msdp) {
- osalDbgCheck(msdp != NULL);
- memset(msdp, 0, sizeof(*msdp));
- msdp->info = &usbhmsdClassDriverInfo;
- osalMutexObjectInit(&msdp->mtx);
-}
-
-#endif
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "hal_usbh.h" + +#if HAL_USBH_USE_MSD + +#if !HAL_USE_USBH +#error "USBHMSD needs USBH" +#endif + +#include <string.h> +#include "usbh/dev/msd.h" +#include "usbh/internal.h" + +//#pragma GCC optimize("Og") + + +#if USBHMSD_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBHMSD_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBHMSD_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBHMSD_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + + + + + +/*===========================================================================*/ +/* USB Class driver loader for MSD */ +/*===========================================================================*/ + +USBHMassStorageDriver USBHMSD[HAL_USBHMSD_MAX_INSTANCES]; + +static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem); +static void _msd_unload(usbh_baseclassdriver_t *drv); + +static const usbh_classdriver_vmt_t class_driver_vmt = { + _msd_load, + _msd_unload +}; + +const usbh_classdriverinfo_t usbhmsdClassDriverInfo = { + 0x08, 0x06, 0x50, "MSD", &class_driver_vmt +}; + +#define MSD_REQ_RESET 0xFF +#define MSD_GET_MAX_LUN 0xFE + +static usbh_baseclassdriver_t *_msd_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { + int i; + USBHMassStorageDriver *msdp; + uint8_t luns; // should declare it here to eliminate 'control bypass initialization' warning + usbh_urbstatus_t stat; // should declare it here to eliminate 'control bypass initialization' warning + + if ((rem < descriptor[0]) || (descriptor[1] != USBH_DT_INTERFACE)) + return NULL; + + const usbh_interface_descriptor_t * const ifdesc = (const usbh_interface_descriptor_t *)descriptor; + + if ((ifdesc->bAlternateSetting != 0) + || (ifdesc->bNumEndpoints < 2) + || (ifdesc->bInterfaceSubClass != 0x06) + || (ifdesc->bInterfaceProtocol != 0x50)) { + return NULL; + } + + /* alloc driver */ + for (i = 0; i < HAL_USBHMSD_MAX_INSTANCES; i++) { + if (USBHMSD[i].dev == NULL) { + msdp = &USBHMSD[i]; + goto alloc_ok; + } + } + + uwarn("Can't alloc MSD driver"); + + /* can't alloc */ + return NULL; + +alloc_ok: + /* initialize the driver's variables */ + msdp->epin.status = USBH_EPSTATUS_UNINITIALIZED; + msdp->epout.status = USBH_EPSTATUS_UNINITIALIZED; + msdp->max_lun = 0; + msdp->tag = 0; + msdp->luns = 0; + msdp->ifnum = ifdesc->bInterfaceNumber; + usbhEPSetName(&dev->ctrl, "MSD[CTRL]"); + + /* parse the configuration descriptor */ + if_iterator_t iif; + generic_iterator_t iep; + iif.iad = 0; + iif.curr = descriptor; + iif.rem = rem; + for (ep_iter_init(&iep, &iif); iep.valid; ep_iter_next(&iep)) { + const usbh_endpoint_descriptor_t *const epdesc = ep_get(&iep); + if ((epdesc->bEndpointAddress & 0x80) && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) { + uinfof("BULK IN endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress); + usbhEPObjectInit(&msdp->epin, dev, epdesc); + usbhEPSetName(&msdp->epin, "MSD[BIN ]"); + } else if (((epdesc->bEndpointAddress & 0x80) == 0) + && (epdesc->bmAttributes == USBH_EPTYPE_BULK)) { + uinfof("BULK OUT endpoint found: bEndpointAddress=%02x", epdesc->bEndpointAddress); + usbhEPObjectInit(&msdp->epout, dev, epdesc); + usbhEPSetName(&msdp->epout, "MSD[BOUT]"); + } else { + uinfof("unsupported endpoint found: bEndpointAddress=%02x, bmAttributes=%02x", + epdesc->bEndpointAddress, epdesc->bmAttributes); + } + } + if ((msdp->epin.status != USBH_EPSTATUS_CLOSED) || (msdp->epout.status != USBH_EPSTATUS_CLOSED)) { + goto deinit; + } + + /* read the number of LUNs */ + uinfo("Reading Max LUN:"); + USBH_DEFINE_BUFFER(uint8_t, buff[4]); + stat = usbhControlRequest(dev, + USBH_CLASSIN(USBH_REQTYPE_INTERFACE, MSD_GET_MAX_LUN, 0, msdp->ifnum), + 1, buff); + if (stat == USBH_URBSTATUS_OK) { + msdp->max_lun = buff[0] + 1; + uinfof("\tmax_lun = %d", msdp->max_lun); + if (msdp->max_lun > HAL_USBHMSD_MAX_LUNS) { + msdp->max_lun = HAL_USBHMSD_MAX_LUNS; + uwarnf("\tUsing max_lun = %d", msdp->max_lun); + } + } else if (stat == USBH_URBSTATUS_STALL) { + uwarn("\tStall, max_lun = 1"); + msdp->max_lun = 1; + } else { + uerr("\tError"); + goto deinit; + } + + /* open the bulk IN/OUT endpoints */ + usbhEPOpen(&msdp->epin); + usbhEPOpen(&msdp->epout); + + /* Alloc one block device per logical unit found */ + luns = msdp->max_lun; + for (i = 0; (luns > 0) && (i < HAL_USBHMSD_MAX_LUNS); i++) { + if (MSBLKD[i].msdp == NULL) { + /* link the new block driver to the list */ + MSBLKD[i].next = msdp->luns; + msdp->luns = &MSBLKD[i]; + MSBLKD[i].msdp = msdp; + + osalSysLock(); + MSBLKD[i].state = BLK_ACTIVE; /* transition directly to active, instead of BLK_STOP */ + osalSysUnlock(); + + /* connect the LUN (TODO: review if it's best to leave the LUN disconnected) */ + usbhmsdLUNConnect(&MSBLKD[i]); + luns--; + } + } + + return (usbh_baseclassdriver_t *)msdp; + +deinit: + /* Here, the enpoints are closed, and the driver is unlinked */ + return NULL; +} + +static void _msd_unload(usbh_baseclassdriver_t *drv) { + osalDbgCheck(drv != NULL); + USBHMassStorageDriver *const msdp = (USBHMassStorageDriver *)drv; + USBHMassStorageLUNDriver *lunp = msdp->luns; + + osalMutexLock(&msdp->mtx); + osalSysLock(); + usbhEPCloseS(&msdp->epin); + usbhEPCloseS(&msdp->epout); + while (lunp) { + lunp->state = BLK_STOP; + lunp = lunp->next; + } + osalSysUnlock(); + osalMutexUnlock(&msdp->mtx); + + /* now that the LUNs are idle, deinit them */ + lunp = msdp->luns; + osalSysLock(); + while (lunp) { + usbhmsdLUNObjectInit(lunp); + lunp = lunp->next; + } + osalSysUnlock(); +} + + +/*===========================================================================*/ +/* MSD Class driver operations (Bulk-Only transport) */ +/*===========================================================================*/ + + + +/* USB Bulk Only Transport SCSI Command block wrapper */ +PACKED_STRUCT { + uint32_t dCBWSignature; + uint32_t dCBWTag; + uint32_t dCBWDataTransferLength; + uint8_t bmCBWFlags; + uint8_t bCBWLUN; + uint8_t bCBWCBLength; + uint8_t CBWCB[16]; +} msd_cbw_t; +#define MSD_CBW_SIGNATURE 0x43425355 +#define MSD_CBWFLAGS_D2H 0x80 +#define MSD_CBWFLAGS_H2D 0x00 + + +/* USB Bulk Only Transport SCSI Command status wrapper */ +PACKED_STRUCT { + uint32_t dCSWSignature; + uint32_t dCSWTag; + uint32_t dCSWDataResidue; + uint8_t bCSWStatus; +} msd_csw_t; +#define MSD_CSW_SIGNATURE 0x53425355 + + +typedef union { + msd_cbw_t cbw; + msd_csw_t csw; +} msd_transaction_t; + +typedef enum { + MSD_TRANSACTIONRESULT_OK, + MSD_TRANSACTIONRESULT_DISCONNECTED, + MSD_TRANSACTIONRESULT_STALL, + MSD_TRANSACTIONRESULT_BUS_ERROR, + MSD_TRANSACTIONRESULT_SYNC_ERROR +} msd_transaction_result_t; + +typedef enum { + MSD_COMMANDRESULT_PASSED = 0, + MSD_COMMANDRESULT_FAILED = 1, + MSD_COMMANDRESULT_PHASE_ERROR = 2 +} msd_command_result_t; + +typedef struct { + msd_transaction_result_t tres; + msd_command_result_t cres; +} msd_result_t; + + +/* ----------------------------------------------------- */ +/* SCSI Commands */ +/* ----------------------------------------------------- */ + +/* Read 10 and Write 10 */ +#define SCSI_CMD_READ_10 0x28 +#define SCSI_CMD_WRITE_10 0x2A + +/* Request sense */ +#define SCSI_CMD_REQUEST_SENSE 0x03 +PACKED_STRUCT { + uint8_t byte[18]; +} scsi_sense_response_t; + +#define SCSI_SENSE_KEY_GOOD 0x00 +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +#define SCSI_SENSE_KEY_NOT_READY 0x02 +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E +#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 +#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 +#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 +#define SCSI_ASENSE_WRITE_PROTECTED 0x27 +#define SCSI_ASENSE_FORMAT_ERROR 0x31 +#define SCSI_ASENSE_INVALID_COMMAND 0x20 +#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 +#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A +#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 +#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 +#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 + +/* Inquiry */ +#define SCSI_CMD_INQUIRY 0x12 +PACKED_STRUCT { + uint8_t peripheral; + uint8_t removable; + uint8_t version; + uint8_t response_data_format; + uint8_t additional_length; + uint8_t sccstp; + uint8_t bqueetc; + uint8_t cmdque; + uint8_t vendorID[8]; + uint8_t productID[16]; + uint8_t productRev[4]; +} scsi_inquiry_response_t; + +/* Read Capacity 10 */ +#define SCSI_CMD_READ_CAPACITY_10 0x25 +PACKED_STRUCT { + uint32_t last_block_addr; + uint32_t block_size; +} scsi_readcapacity10_response_t; + +/* Start/Stop Unit */ +#define SCSI_CMD_START_STOP_UNIT 0x1B +PACKED_STRUCT { + uint8_t op_code; + uint8_t lun_immed; + uint8_t res1; + uint8_t res2; + uint8_t loej_start; + uint8_t control; +} scsi_startstopunit_request_t; + +/* test unit ready */ +#define SCSI_CMD_TEST_UNIT_READY 0x00 + +/* Other commands, TODO: use or remove them +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define SCSI_CMD_VERIFY_10 0x2F +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +#define SCSI_CMD_MODE_SENSE_6 0x1A +*/ + +static inline void _prepare_cbw(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp) { + tran->cbw.bCBWLUN = (uint8_t)(lunp - &lunp->msdp->luns[0]); + memset(&tran->cbw.CBWCB, 0, sizeof(tran->cbw.CBWCB)); +} + +static msd_transaction_result_t _msd_transaction(msd_transaction_t *tran, USBHMassStorageLUNDriver *lunp, void *data) { + + uint32_t actual_len; + usbh_urbstatus_t status; + + tran->cbw.dCBWSignature = MSD_CBW_SIGNATURE; + tran->cbw.dCBWTag = ++lunp->msdp->tag; + + /* control phase */ + status = usbhBulkTransfer(&lunp->msdp->epout, &tran->cbw, + sizeof(tran->cbw), &actual_len, MS2ST(1000)); + + if (status == USBH_URBSTATUS_CANCELLED) { + uerr("\tMSD: Control phase: USBH_URBSTATUS_CANCELLED"); + return MSD_TRANSACTIONRESULT_DISCONNECTED; + } else if (status == USBH_URBSTATUS_STALL) { + uerr("\tMSD: Control phase: USBH_URBSTATUS_STALL"); + return MSD_TRANSACTIONRESULT_STALL; + } else if (status != USBH_URBSTATUS_OK) { + uerrf("\tMSD: Control phase: status = %d, != OK", status); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } else if (actual_len != sizeof(tran->cbw)) { + uerrf("\tMSD: Control phase: wrong actual_len = %d", actual_len); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } + + + /* data phase */ + if (tran->cbw.dCBWDataTransferLength) { + status = usbhBulkTransfer( + tran->cbw.bmCBWFlags & MSD_CBWFLAGS_D2H ? &lunp->msdp->epin : &lunp->msdp->epout, + data, + tran->cbw.dCBWDataTransferLength, + &actual_len, MS2ST(20000)); + + if (status == USBH_URBSTATUS_CANCELLED) { + uerr("\tMSD: Data phase: USBH_URBSTATUS_CANCELLED"); + return MSD_TRANSACTIONRESULT_DISCONNECTED; + } else if (status == USBH_URBSTATUS_STALL) { + uerr("\tMSD: Data phase: USBH_URBSTATUS_STALL"); + return MSD_TRANSACTIONRESULT_STALL; + } else if (status != USBH_URBSTATUS_OK) { + uerrf("\tMSD: Data phase: status = %d, != OK", status); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } else if (actual_len != tran->cbw.dCBWDataTransferLength) { + uerrf("\tMSD: Data phase: wrong actual_len = %d", actual_len); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } + } + + + /* status phase */ + status = usbhBulkTransfer(&lunp->msdp->epin, &tran->csw, + sizeof(tran->csw), &actual_len, MS2ST(1000)); + + if (status == USBH_URBSTATUS_CANCELLED) { + uerr("\tMSD: Status phase: USBH_URBSTATUS_CANCELLED"); + return MSD_TRANSACTIONRESULT_DISCONNECTED; + } else if (status == USBH_URBSTATUS_STALL) { + uerr("\tMSD: Status phase: USBH_URBSTATUS_STALL"); + return MSD_TRANSACTIONRESULT_STALL; + } else if (status != USBH_URBSTATUS_OK) { + uerrf("\tMSD: Status phase: status = %d, != OK", status); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } else if (actual_len != sizeof(tran->csw)) { + uerrf("\tMSD: Status phase: wrong actual_len = %d", actual_len); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } else if (tran->csw.dCSWSignature != MSD_CSW_SIGNATURE) { + uerr("\tMSD: Status phase: wrong signature"); + return MSD_TRANSACTIONRESULT_BUS_ERROR; + } else if (tran->csw.dCSWTag != lunp->msdp->tag) { + uerrf("\tMSD: Status phase: wrong tag (expected %d, got %d)", + lunp->msdp->tag, tran->csw.dCSWTag); + return MSD_TRANSACTIONRESULT_SYNC_ERROR; + } + + if (tran->csw.dCSWDataResidue) { + uwarnf("\tMSD: Residue=%d", tran->csw.dCSWDataResidue); + } + + return MSD_TRANSACTIONRESULT_OK; +} + + +static msd_result_t scsi_inquiry(USBHMassStorageLUNDriver *lunp, scsi_inquiry_response_t *resp) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = sizeof(scsi_inquiry_response_t); + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H; + transaction.cbw.bCBWCBLength = 6; + transaction.cbw.CBWCB[0] = SCSI_CMD_INQUIRY; + transaction.cbw.CBWCB[4] = sizeof(scsi_inquiry_response_t); + + res.tres = _msd_transaction(&transaction, lunp, resp); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + +static msd_result_t scsi_requestsense(USBHMassStorageLUNDriver *lunp, scsi_sense_response_t *resp) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = sizeof(scsi_sense_response_t); + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H; + transaction.cbw.bCBWCBLength = 12; + transaction.cbw.CBWCB[0] = SCSI_CMD_REQUEST_SENSE; + transaction.cbw.CBWCB[4] = sizeof(scsi_sense_response_t); + + res.tres = _msd_transaction(&transaction, lunp, resp); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + +static msd_result_t scsi_testunitready(USBHMassStorageLUNDriver *lunp) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = 0; + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H; + transaction.cbw.bCBWCBLength = 6; + transaction.cbw.CBWCB[0] = SCSI_CMD_TEST_UNIT_READY; + + res.tres = _msd_transaction(&transaction, lunp, NULL); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + +static msd_result_t scsi_readcapacity10(USBHMassStorageLUNDriver *lunp, scsi_readcapacity10_response_t *resp) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = sizeof(scsi_readcapacity10_response_t); + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H; + transaction.cbw.bCBWCBLength = 12; + transaction.cbw.CBWCB[0] = SCSI_CMD_READ_CAPACITY_10; + + res.tres = _msd_transaction(&transaction, lunp, resp); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + + +static msd_result_t scsi_read10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, uint8_t *data) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size; + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_D2H; + transaction.cbw.bCBWCBLength = 10; + transaction.cbw.CBWCB[0] = SCSI_CMD_READ_10; + transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24); + transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16); + transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8); + transaction.cbw.CBWCB[5] = (uint8_t)(lba); + transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8); + transaction.cbw.CBWCB[8] = (uint8_t)(n); + + res.tres = _msd_transaction(&transaction, lunp, data); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + +static msd_result_t scsi_write10(USBHMassStorageLUNDriver *lunp, uint32_t lba, uint16_t n, const uint8_t *data) { + msd_transaction_t transaction; + msd_result_t res; + + _prepare_cbw(&transaction, lunp); + transaction.cbw.dCBWDataTransferLength = n * lunp->info.blk_size; + transaction.cbw.bmCBWFlags = MSD_CBWFLAGS_H2D; + transaction.cbw.bCBWCBLength = 10; + transaction.cbw.CBWCB[0] = SCSI_CMD_WRITE_10; + transaction.cbw.CBWCB[2] = (uint8_t)(lba >> 24); + transaction.cbw.CBWCB[3] = (uint8_t)(lba >> 16); + transaction.cbw.CBWCB[4] = (uint8_t)(lba >> 8); + transaction.cbw.CBWCB[5] = (uint8_t)(lba); + transaction.cbw.CBWCB[7] = (uint8_t)(n >> 8); + transaction.cbw.CBWCB[8] = (uint8_t)(n); + + res.tres = _msd_transaction(&transaction, lunp, (uint8_t *)data); + if (res.tres == MSD_TRANSACTIONRESULT_OK) { + res.cres = (msd_command_result_t) transaction.csw.bCSWStatus; + } + return res; +} + + + +/*===========================================================================*/ +/* Block driver data/functions */ +/*===========================================================================*/ + +USBHMassStorageLUNDriver MSBLKD[HAL_USBHMSD_MAX_LUNS]; + +static const struct USBHMassStorageDriverVMT blk_vmt = { + (bool (*)(void *))usbhmsdLUNIsInserted, + (bool (*)(void *))usbhmsdLUNIsProtected, + (bool (*)(void *))usbhmsdLUNConnect, + (bool (*)(void *))usbhmsdLUNDisconnect, + (bool (*)(void *, uint32_t, uint8_t *, uint32_t))usbhmsdLUNRead, + (bool (*)(void *, uint32_t, const uint8_t *, uint32_t))usbhmsdLUNWrite, + (bool (*)(void *))usbhmsdLUNSync, + (bool (*)(void *, BlockDeviceInfo *))usbhmsdLUNGetInfo +}; + + + +static uint32_t _requestsense(USBHMassStorageLUNDriver *lunp) { + scsi_sense_response_t sense; + msd_result_t res; + + res = scsi_requestsense(lunp, &sense); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tREQUEST SENSE: Transaction error"); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + uerr("\tREQUEST SENSE: Command Failed"); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tREQUEST SENSE: Command Phase Error"); + goto failed; + } + + uerrf("\tREQUEST SENSE: Sense key=%x, ASC=%02x, ASCQ=%02x", + sense.byte[2] & 0xf, sense.byte[12], sense.byte[13]); + + return (sense.byte[2] & 0xf) | (sense.byte[12] << 8) | (sense.byte[13] << 16); + +failed: + return 0xffffffff; +} + +void usbhmsdLUNObjectInit(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + memset(lunp, 0, sizeof(*lunp)); + lunp->vmt = &blk_vmt; + lunp->state = BLK_STOP; + /* Unnecessary because of the memset: + lunp->msdp = NULL; + lunp->next = NULL; + lunp->info.* = 0; + */ +} + +void usbhmsdLUNStart(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + osalSysLock(); + osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE), + "invalid state"); + //TODO: complete + //lunp->state = BLK_ACTIVE; + osalSysUnlock(); +} + +void usbhmsdLUNStop(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + osalSysLock(); + osalDbgAssert((lunp->state == BLK_STOP) || (lunp->state == BLK_ACTIVE), + "invalid state"); + //TODO: complete + //lunp->state = BLK_STOP; + osalSysUnlock(); +} + +bool usbhmsdLUNConnect(USBHMassStorageLUNDriver *lunp) { + USBHMassStorageDriver *const msdp = lunp->msdp; + msd_result_t res; + + osalDbgCheck(msdp != NULL); + osalSysLock(); + //osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY), + // "invalid state"); + if (lunp->state == BLK_READY) { + osalSysUnlock(); + return HAL_SUCCESS; + } else if (lunp->state != BLK_ACTIVE) { + osalSysUnlock(); + return HAL_FAILED; + } + lunp->state = BLK_CONNECTING; + osalSysUnlock(); + + osalMutexLock(&msdp->mtx); + + USBH_DEFINE_BUFFER(union { + scsi_inquiry_response_t inq; + scsi_readcapacity10_response_t cap; }, u); + + uinfo("INQUIRY..."); + res = scsi_inquiry(lunp, &u.inq); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tINQUIRY: Transaction error"); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + uerr("\tINQUIRY: Command Failed"); + _requestsense(lunp); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tINQUIRY: Command Phase Error"); + goto failed; + } + + uinfof("\tPDT=%02x", u.inq.peripheral & 0x1f); + if (u.inq.peripheral != 0) { + uerr("\tUnsupported PDT"); + goto failed; + } + + // Test if unit ready + uint8_t i; + for (i = 0; i < 10; i++) { + uinfo("TEST UNIT READY..."); + res = scsi_testunitready(lunp); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tTEST UNIT READY: Transaction error"); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + uerr("\tTEST UNIT READY: Command Failed"); + _requestsense(lunp); + continue; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tTEST UNIT READY: Command Phase Error"); + goto failed; + } + uinfo("\tReady."); + break; + // osalThreadSleepMilliseconds(200); // will raise 'code is unreachable' warning + } + if (i == 10) goto failed; + + // Read capacity + uinfo("READ CAPACITY(10)..."); + res = scsi_readcapacity10(lunp, &u.cap); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tREAD CAPACITY(10): Transaction error"); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + uerr("\tREAD CAPACITY(10): Command Failed"); + _requestsense(lunp); + goto failed; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tREAD CAPACITY(10): Command Phase Error"); + goto failed; + } + lunp->info.blk_size = __REV(u.cap.block_size); + lunp->info.blk_num = __REV(u.cap.last_block_addr) + 1; + uinfof("\tBlock size=%dbytes, blocks=%u (~%u MB)", lunp->info.blk_size, lunp->info.blk_num, + (uint32_t)(((uint64_t)lunp->info.blk_size * lunp->info.blk_num) / (1024UL * 1024UL))); + + uinfo("MSD Connected."); + + osalMutexUnlock(&msdp->mtx); + osalSysLock(); + lunp->state = BLK_READY; + osalSysUnlock(); + + return HAL_SUCCESS; + + /* Connection failed, state reset to BLK_ACTIVE.*/ +failed: + osalMutexUnlock(&msdp->mtx); + osalSysLock(); + lunp->state = BLK_ACTIVE; + osalSysUnlock(); + return HAL_FAILED; +} + + +bool usbhmsdLUNDisconnect(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + osalSysLock(); + osalDbgAssert((lunp->state == BLK_ACTIVE) || (lunp->state == BLK_READY), + "invalid state"); + if (lunp->state == BLK_ACTIVE) { + osalSysUnlock(); + return HAL_SUCCESS; + } + lunp->state = BLK_DISCONNECTING; + osalSysUnlock(); + + //TODO: complete + + osalSysLock(); + lunp->state = BLK_ACTIVE; + osalSysUnlock(); + return HAL_SUCCESS; +} + +bool usbhmsdLUNRead(USBHMassStorageLUNDriver *lunp, uint32_t startblk, + uint8_t *buffer, uint32_t n) { + + osalDbgCheck(lunp != NULL); + bool ret = HAL_FAILED; + uint16_t blocks; + msd_result_t res; + + osalSysLock(); + if (lunp->state != BLK_READY) { + osalSysUnlock(); + return ret; + } + lunp->state = BLK_READING; + osalSysUnlock(); + + osalMutexLock(&lunp->msdp->mtx); + while (n) { + if (n > 0xffff) { + blocks = 0xffff; + } else { + blocks = (uint16_t)n; + } + res = scsi_read10(lunp, startblk, blocks, buffer); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tREAD (10): Transaction error"); + goto exit; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + //TODO: request sense, and act appropriately + uerr("\tREAD (10): Command Failed"); + _requestsense(lunp); + goto exit; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tREAD (10): Command Phase Error"); + goto exit; + } + n -= blocks; + startblk += blocks; + buffer += blocks * lunp->info.blk_size; + } + + ret = HAL_SUCCESS; + +exit: + osalMutexUnlock(&lunp->msdp->mtx); + osalSysLock(); + if (lunp->state == BLK_READING) { + lunp->state = BLK_READY; + } else { + osalDbgCheck(lunp->state == BLK_STOP); + uwarn("MSD: State = BLK_STOP"); + } + osalSysUnlock(); + return ret; +} + +bool usbhmsdLUNWrite(USBHMassStorageLUNDriver *lunp, uint32_t startblk, + const uint8_t *buffer, uint32_t n) { + + osalDbgCheck(lunp != NULL); + bool ret = HAL_FAILED; + uint16_t blocks; + msd_result_t res; + + osalSysLock(); + if (lunp->state != BLK_READY) { + osalSysUnlock(); + return ret; + } + lunp->state = BLK_WRITING; + osalSysUnlock(); + + osalMutexLock(&lunp->msdp->mtx); + while (n) { + if (n > 0xffff) { + blocks = 0xffff; + } else { + blocks = (uint16_t)n; + } + res = scsi_write10(lunp, startblk, blocks, buffer); + if (res.tres != MSD_TRANSACTIONRESULT_OK) { + uerr("\tWRITE (10): Transaction error"); + goto exit; + } else if (res.cres == MSD_COMMANDRESULT_FAILED) { + //TODO: request sense, and act appropriately + uerr("\tWRITE (10): Command Failed"); + _requestsense(lunp); + goto exit; + } else if (res.cres == MSD_COMMANDRESULT_PHASE_ERROR) { + //TODO: Do reset, etc. + uerr("\tWRITE (10): Command Phase Error"); + goto exit; + } + n -= blocks; + startblk += blocks; + buffer += blocks * lunp->info.blk_size; + } + + ret = HAL_SUCCESS; + +exit: + osalMutexUnlock(&lunp->msdp->mtx); + osalSysLock(); + if (lunp->state == BLK_WRITING) { + lunp->state = BLK_READY; + } else { + osalDbgCheck(lunp->state == BLK_STOP); + uwarn("MSD: State = BLK_STOP"); + } + osalSysUnlock(); + return ret; +} + +bool usbhmsdLUNSync(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + (void)lunp; + //TODO: Do SCSI Sync + return HAL_SUCCESS; +} + +bool usbhmsdLUNGetInfo(USBHMassStorageLUNDriver *lunp, BlockDeviceInfo *bdip) { + osalDbgCheck(lunp != NULL); + osalDbgCheck(bdip != NULL); + *bdip = lunp->info; + return HAL_SUCCESS; +} + +bool usbhmsdLUNIsInserted(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + blkstate_t state; + osalSysLock(); + state = lunp->state; + osalSysUnlock(); + return (state >= BLK_ACTIVE); +} + +bool usbhmsdLUNIsProtected(USBHMassStorageLUNDriver *lunp) { + osalDbgCheck(lunp != NULL); + return FALSE; +} + +void usbhmsdObjectInit(USBHMassStorageDriver *msdp) { + osalDbgCheck(msdp != NULL); + memset(msdp, 0, sizeof(*msdp)); + msdp->info = &usbhmsdClassDriverInfo; + osalMutexObjectInit(&msdp->mtx); +} + +#endif diff --git a/os/hal/src/usbh/usbh_uvc.c b/os/hal/src/usbh/hal_usbh_uvc.c index 2fb2563..09a0f1d 100644 --- a/os/hal/src/usbh/usbh_uvc.c +++ b/os/hal/src/usbh/hal_usbh_uvc.c @@ -1,89 +1,89 @@ -/*
- ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio
- Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail)
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "hal.h"
-#include "usbh.h"
-
-#if HAL_USBH_USE_UVC
-
-#if !HAL_USE_USBH
-#error "USBHUVC needs HAL_USE_USBH"
-#endif
-
-#if !HAL_USBH_USE_IAD
-#error "USBHUVC needs HAL_USBH_USE_IAD"
-#endif
-
-#if USBHUVC_DEBUG_ENABLE_TRACE
-#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define udbgf(f, ...) do {} while(0)
-#define udbg(f, ...) do {} while(0)
-#endif
-
-#if USBHUVC_DEBUG_ENABLE_INFO
-#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uinfof(f, ...) do {} while(0)
-#define uinfo(f, ...) do {} while(0)
-#endif
-
-#if USBHUVC_DEBUG_ENABLE_WARNINGS
-#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uwarnf(f, ...) do {} while(0)
-#define uwarn(f, ...) do {} while(0)
-#endif
-
-#if USBHUVC_DEBUG_ENABLE_ERRORS
-#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__)
-#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__)
-#else
-#define uerrf(f, ...) do {} while(0)
-#define uerr(f, ...) do {} while(0)
-#endif
-
-
-static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev,
- const uint8_t *descriptor, uint16_t rem);
-static void uvc_unload(usbh_baseclassdriver_t *drv);
-
-static const usbh_classdriver_vmt_t class_driver_vmt = {
- uvc_load,
- uvc_unload
-};
-const usbh_classdriverinfo_t usbhuvcClassDriverInfo = {
- 0x0e, 0x03, 0x00, "UVC", &class_driver_vmt
-};
-
-
-static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) {
- (void)dev;
- (void)descriptor;
- (void)rem;
- return NULL;
-}
-
-static void uvc_unload(usbh_baseclassdriver_t *drv) {
- (void)drv;
-}
-
-#endif
-
+/* + ChibiOS - Copyright (C) 2006..2015 Giovanni Di Sirio + Copyright (C) 2015 Diego Ismirlian, TISA, (dismirlian (at) google's mail) + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "hal.h" +#include "hal_usbh.h" + +#if HAL_USBH_USE_UVC + +#if !HAL_USE_USBH +#error "USBHUVC needs HAL_USE_USBH" +#endif + +#if !HAL_USBH_USE_IAD +#error "USBHUVC needs HAL_USBH_USE_IAD" +#endif + +#if USBHUVC_DEBUG_ENABLE_TRACE +#define udbgf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define udbg(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define udbgf(f, ...) do {} while(0) +#define udbg(f, ...) do {} while(0) +#endif + +#if USBHUVC_DEBUG_ENABLE_INFO +#define uinfof(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uinfo(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uinfof(f, ...) do {} while(0) +#define uinfo(f, ...) do {} while(0) +#endif + +#if USBHUVC_DEBUG_ENABLE_WARNINGS +#define uwarnf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uwarn(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uwarnf(f, ...) do {} while(0) +#define uwarn(f, ...) do {} while(0) +#endif + +#if USBHUVC_DEBUG_ENABLE_ERRORS +#define uerrf(f, ...) usbDbgPrintf(f, ##__VA_ARGS__) +#define uerr(f, ...) usbDbgPuts(f, ##__VA_ARGS__) +#else +#define uerrf(f, ...) do {} while(0) +#define uerr(f, ...) do {} while(0) +#endif + + +static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, + const uint8_t *descriptor, uint16_t rem); +static void uvc_unload(usbh_baseclassdriver_t *drv); + +static const usbh_classdriver_vmt_t class_driver_vmt = { + uvc_load, + uvc_unload +}; +const usbh_classdriverinfo_t usbhuvcClassDriverInfo = { + 0x0e, 0x03, 0x00, "UVC", &class_driver_vmt +}; + + +static usbh_baseclassdriver_t *uvc_load(usbh_device_t *dev, const uint8_t *descriptor, uint16_t rem) { + (void)dev; + (void)descriptor; + (void)rem; + return NULL; +} + +static void uvc_unload(usbh_baseclassdriver_t *drv) { + (void)drv; +} + +#endif + |