git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6224 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2013-08-25 09:37:34 +00:00
parent de38efdc97
commit 5901a354ef
14 changed files with 2044 additions and 50 deletions

View File

@ -13,9 +13,11 @@ HALSRC = ${CHIBIOS}/os/hal/src/hal.c \
${CHIBIOS}/os/hal/src/pal.c \ ${CHIBIOS}/os/hal/src/pal.c \
${CHIBIOS}/os/hal/src/pwm.c \ ${CHIBIOS}/os/hal/src/pwm.c \
${CHIBIOS}/os/hal/src/serial.c \ ${CHIBIOS}/os/hal/src/serial.c \
${CHIBIOS}/os/hal/src/serial_usb.c \
${CHIBIOS}/os/hal/src/spi.c \ ${CHIBIOS}/os/hal/src/spi.c \
${CHIBIOS}/os/hal/src/st.c \ ${CHIBIOS}/os/hal/src/st.c \
${CHIBIOS}/os/hal/src/uart.c \ ${CHIBIOS}/os/hal/src/uart.c \
${CHIBIOS}/os/hal/src/usb.c
# Required include directories # Required include directories
HALINC = ${CHIBIOS}/os/hal/include HALINC = ${CHIBIOS}/os/hal/include

View File

@ -60,11 +60,11 @@
#include "spi.h" #include "spi.h"
#include "st.h" #include "st.h"
#include "uart.h" #include "uart.h"
//#include "usb.h" #include "usb.h"
/* Complex drivers.*/ /* Complex drivers.*/
#include "mmc_spi.h" #include "mmc_spi.h"
//#include "serial_usb.h" #include "serial_usb.h"
/*===========================================================================*/ /*===========================================================================*/
/* Driver constants. */ /* Driver constants. */

View File

@ -372,7 +372,7 @@ extern "C" {
this module will use the ChibiOS queues code.*/ this module will use the ChibiOS queues code.*/
#define qSizeI(qp) chQSizeI(qp) #define qSizeI(qp) chQSizeI(qp)
#define qSpaceI(qp) chQSpaceI(qp) #define qSpaceI(qp) chQSpaceI(qp)
#define qGetLink(qp) chQGetLink(qp) #define qGetLink(qp) chQGetLinkX(qp)
#define iqGetFullI(iqp) chIQGetFullI(iqp) #define iqGetFullI(iqp) chIQGetFullI(iqp)
#define iqGetEmptyI(iqp) chIQGetEmptyI(iqp) #define iqGetEmptyI(iqp) chIQGetEmptyI(iqp)
#define iqIsEmptyI(iqp) chIQIsEmptyI(iqp) #define iqIsEmptyI(iqp) chIQIsEmptyI(iqp)

233
os/hal/include/serial_usb.h Normal file
View File

@ -0,0 +1,233 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file serial_usb.h
* @brief Serial over USB Driver macros and structures.
*
* @addtogroup SERIAL_USB
* @{
*/
#ifndef _SERIAL_USB_H_
#define _SERIAL_USB_H_
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name CDC specific messages.
* @{
*/
#define CDC_SEND_ENCAPSULATED_COMMAND 0x00
#define CDC_GET_ENCAPSULATED_RESPONSE 0x01
#define CDC_SET_COMM_FEATURE 0x02
#define CDC_GET_COMM_FEATURE 0x03
#define CDC_CLEAR_COMM_FEATURE 0x04
#define CDC_SET_AUX_LINE_STATE 0x10
#define CDC_SET_HOOK_STATE 0x11
#define CDC_PULSE_SETUP 0x12
#define CDC_SEND_PULSE 0x13
#define CDC_SET_PULSE_TIME 0x14
#define CDC_RING_AUX_JACK 0x15
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#define CDC_SEND_BREAK 0x23
#define CDC_SET_RINGER_PARMS 0x30
#define CDC_GET_RINGER_PARMS 0x31
#define CDC_SET_OPERATION_PARMS 0x32
#define CDC_GET_OPERATION_PARMS 0x33
/** @} */
/**
* @name Line Control bit definitions.
* @{
*/
#define LC_STOP_1 0
#define LC_STOP_1P5 1
#define LC_STOP_2 2
#define LC_PARITY_NONE 0
#define LC_PARITY_ODD 1
#define LC_PARITY_EVEN 2
#define LC_PARITY_MARK 3
#define LC_PARITY_SPACE 4
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name SERIAL_USB configuration options
* @{
*/
/**
* @brief Serial over USB buffers size.
* @details Configuration parameter, the buffer size must be a multiple of
* the USB data endpoint maximum packet size.
* @note The default is 256 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_USB_BUFFERS_SIZE 256
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !HAL_USE_USB
#error "Serial over USB Driver requires HAL_USE_USB"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of Line Coding structure.
*/
typedef struct {
uint8_t dwDTERate[4];
uint8_t bCharFormat;
uint8_t bParityType;
uint8_t bDataBits;
} cdc_linecoding_t;
/**
* @brief Driver state machine possible states.
*/
typedef enum {
SDU_UNINIT = 0, /**< Not initialized. */
SDU_STOP = 1, /**< Stopped. */
SDU_READY = 2 /**< Ready. */
} sdustate_t;
/**
* @brief Structure representing a serial over USB driver.
*/
typedef struct SerialUSBDriver SerialUSBDriver;
/**
* @brief Serial over USB Driver configuration structure.
* @details An instance of this structure must be passed to @p sduStart()
* in order to configure and start the driver operations.
*/
typedef struct {
/**
* @brief USB driver to use.
*/
USBDriver *usbp;
/**
* @brief Bulk IN endpoint used for outgoing data transfer.
*/
usbep_t bulk_in;
/**
* @brief Bulk OUT endpoint used for incoming data transfer.
*/
usbep_t bulk_out;
/**
* @brief Interrupt IN endpoint used for notifications.
*/
usbep_t int_in;
} SerialUSBConfig;
/**
* @brief @p SerialDriver specific data.
*/
#define _serial_usb_driver_data \
_base_asynchronous_channel_data \
/* Driver state.*/ \
sdustate_t state; \
/* Input queue.*/ \
input_queue_t iqueue; \
/* Output queue.*/ \
output_queue_t oqueue; \
/* Input buffer.*/ \
uint8_t ib[SERIAL_USB_BUFFERS_SIZE]; \
/* Output buffer.*/ \
uint8_t ob[SERIAL_USB_BUFFERS_SIZE]; \
/* End of the mandatory fields.*/ \
/* Current configuration data.*/ \
const SerialUSBConfig *config;
/**
* @brief @p SerialUSBDriver specific methods.
*/
#define _serial_usb_driver_methods \
_base_asynchronous_channel_methods
/**
* @extends BaseAsynchronousChannelVMT
*
* @brief @p SerialDriver virtual methods table.
*/
struct SerialUSBDriverVMT {
_serial_usb_driver_methods
};
/**
* @extends BaseAsynchronousChannel
*
* @brief Full duplex serial driver class.
* @details This class extends @p BaseAsynchronousChannel by adding physical
* I/O queues.
*/
struct SerialUSBDriver {
/** @brief Virtual Methods Table.*/
const struct SerialUSBDriverVMT *vmt;
_serial_usb_driver_data
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void sduInit(void);
void sduObjectInit(SerialUSBDriver *sdp);
void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config);
void sduStop(SerialUSBDriver *sdup);
void sduConfigureHookI(SerialUSBDriver *sdup);
bool_t sduRequestsHook(USBDriver *usbp);
void sduDataTransmitted(USBDriver *usbp, usbep_t ep);
void sduDataReceived(USBDriver *usbp, usbep_t ep);
void sduInterruptTransmitted(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SERIAL_USB */
#endif /* _SERIAL_USB_H_ */
/** @} */

572
os/hal/include/usb.h Normal file
View File

@ -0,0 +1,572 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file usb.h
* @brief USB Driver macros and structures.
*
* @addtogroup USB
* @{
*/
#ifndef _USB_H_
#define _USB_H_
#if HAL_USE_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#define USB_RTYPE_DIR_MASK 0x80
#define USB_RTYPE_DIR_HOST2DEV 0x00
#define USB_RTYPE_DIR_DEV2HOST 0x80
#define USB_RTYPE_TYPE_MASK 0x60
#define USB_RTYPE_TYPE_STD 0x00
#define USB_RTYPE_TYPE_CLASS 0x20
#define USB_RTYPE_TYPE_VENDOR 0x40
#define USB_RTYPE_TYPE_RESERVED 0x60
#define USB_RTYPE_RECIPIENT_MASK 0x1F
#define USB_RTYPE_RECIPIENT_DEVICE 0x00
#define USB_RTYPE_RECIPIENT_INTERFACE 0x01
#define USB_RTYPE_RECIPIENT_ENDPOINT 0x02
#define USB_RTYPE_RECIPIENT_OTHER 0x03
#define USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
#define USB_REQ_SET_FEATURE 3
#define USB_REQ_SET_ADDRESS 5
#define USB_REQ_GET_DESCRIPTOR 6
#define USB_REQ_SET_DESCRIPTOR 7
#define USB_REQ_GET_CONFIGURATION 8
#define USB_REQ_SET_CONFIGURATION 9
#define USB_REQ_GET_INTERFACE 10
#define USB_REQ_SET_INTERFACE 11
#define USB_REQ_SYNCH_FRAME 12
#define USB_DESCRIPTOR_DEVICE 1
#define USB_DESCRIPTOR_CONFIGURATION 2
#define USB_DESCRIPTOR_STRING 3
#define USB_DESCRIPTOR_INTERFACE 4
#define USB_DESCRIPTOR_ENDPOINT 5
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 6
#define USB_DESCRIPTOR_OTHER_SPEED_CFG 7
#define USB_DESCRIPTOR_INTERFACE_POWER 8
#define USB_DESCRIPTOR_INTERFACE_ASSOCIATION 11
#define USB_FEATURE_ENDPOINT_HALT 0
#define USB_FEATURE_DEVICE_REMOTE_WAKEUP 1
#define USB_FEATURE_TEST_MODE 2
#define USB_EARLY_SET_ADDRESS 0
#define USB_LATE_SET_ADDRESS 1
/**
* @name Helper macros for USB descriptors
* @{
*/
/**
* @brief Helper macro for index values into descriptor strings.
*/
#define USB_DESC_INDEX(i) ((uint8_t)(i))
/**
* @brief Helper macro for byte values into descriptor strings.
*/
#define USB_DESC_BYTE(b) ((uint8_t)(b))
/**
* @brief Helper macro for word values into descriptor strings.
*/
#define USB_DESC_WORD(w) \
(uint8_t)((w) & 255), \
(uint8_t)(((w) >> 8) & 255)
/**
* @brief Helper macro for BCD values into descriptor strings.
*/
#define USB_DESC_BCD(bcd) \
(uint8_t)((bcd) & 255), \
(uint8_t)(((bcd) >> 8) & 255)
/**
* @brief Device Descriptor helper macro.
*/
#define USB_DESC_DEVICE(bcdUSB, bDeviceClass, bDeviceSubClass, \
bDeviceProtocol, bMaxPacketSize, idVendor, \
idProduct, bcdDevice, iManufacturer, \
iProduct, iSerialNumber, bNumConfigurations) \
USB_DESC_BYTE(18), \
USB_DESC_BYTE(USB_DESCRIPTOR_DEVICE), \
USB_DESC_BCD(bcdUSB), \
USB_DESC_BYTE(bDeviceClass), \
USB_DESC_BYTE(bDeviceSubClass), \
USB_DESC_BYTE(bDeviceProtocol), \
USB_DESC_BYTE(bMaxPacketSize), \
USB_DESC_WORD(idVendor), \
USB_DESC_WORD(idProduct), \
USB_DESC_BCD(bcdDevice), \
USB_DESC_INDEX(iManufacturer), \
USB_DESC_INDEX(iProduct), \
USB_DESC_INDEX(iSerialNumber), \
USB_DESC_BYTE(bNumConfigurations)
/**
* @brief Configuration Descriptor helper macro.
*/
#define USB_DESC_CONFIGURATION(wTotalLength, bNumInterfaces, \
bConfigurationValue, iConfiguration, \
bmAttributes, bMaxPower) \
USB_DESC_BYTE(9), \
USB_DESC_BYTE(USB_DESCRIPTOR_CONFIGURATION), \
USB_DESC_WORD(wTotalLength), \
USB_DESC_BYTE(bNumInterfaces), \
USB_DESC_BYTE(bConfigurationValue), \
USB_DESC_INDEX(iConfiguration), \
USB_DESC_BYTE(bmAttributes), \
USB_DESC_BYTE(bMaxPower)
/**
* @brief Interface Descriptor helper macro.
*/
#define USB_DESC_INTERFACE(bInterfaceNumber, bAlternateSetting, \
bNumEndpoints, bInterfaceClass, \
bInterfaceSubClass, bInterfaceProtocol, \
iInterface) \
USB_DESC_BYTE(9), \
USB_DESC_BYTE(USB_DESCRIPTOR_INTERFACE), \
USB_DESC_BYTE(bInterfaceNumber), \
USB_DESC_BYTE(bAlternateSetting), \
USB_DESC_BYTE(bNumEndpoints), \
USB_DESC_BYTE(bInterfaceClass), \
USB_DESC_BYTE(bInterfaceSubClass), \
USB_DESC_BYTE(bInterfaceProtocol), \
USB_DESC_INDEX(iInterface)
/**
* @brief Interface Association Descriptor helper macro.
*/
#define USB_DESC_INTERFACE_ASSOCIATION(bFirstInterface, \
bInterfaceCount, bFunctionClass, \
bFunctionSubClass, bFunctionProcotol, \
iInterface) \
USB_DESC_BYTE(8), \
USB_DESC_BYTE(USB_DESCRIPTOR_INTERFACE_ASSOCIATION), \
USB_DESC_BYTE(bFirstInterface), \
USB_DESC_BYTE(bInterfaceCount), \
USB_DESC_BYTE(bFunctionClass), \
USB_DESC_BYTE(bFunctionSubClass), \
USB_DESC_BYTE(bFunctionProcotol), \
USB_DESC_INDEX(iInterface)
/**
* @brief Endpoint Descriptor helper macro.
*/
#define USB_DESC_ENDPOINT(bEndpointAddress, bmAttributes, wMaxPacketSize, \
bInterval) \
USB_DESC_BYTE(7), \
USB_DESC_BYTE(USB_DESCRIPTOR_ENDPOINT), \
USB_DESC_BYTE(bEndpointAddress), \
USB_DESC_BYTE(bmAttributes), \
USB_DESC_WORD(wMaxPacketSize), \
USB_DESC_BYTE(bInterval)
/** @} */
/**
* @name Endpoint types and settings
* @{
*/
#define USB_EP_MODE_TYPE 0x0003 /**< Endpoint type mask. */
#define USB_EP_MODE_TYPE_CTRL 0x0000 /**< Control endpoint. */
#define USB_EP_MODE_TYPE_ISOC 0x0001 /**< Isochronous endpoint. */
#define USB_EP_MODE_TYPE_BULK 0x0002 /**< Bulk endpoint. */
#define USB_EP_MODE_TYPE_INTR 0x0003 /**< Interrupt endpoint. */
#define USB_EP_MODE_LINEAR_BUFFER 0x0000 /**< Linear buffer mode. */
#define USB_EP_MODE_QUEUE_BUFFER 0x0010 /**< Queue buffer mode. */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an USB driver.
*/
typedef struct USBDriver USBDriver;
/**
* @brief Type of an endpoint identifier.
*/
typedef uint8_t usbep_t;
/**
* @brief Type of a driver state machine possible states.
*/
typedef enum {
USB_UNINIT = 0, /**< Not initialized. */
USB_STOP = 1, /**< Stopped. */
USB_READY = 2, /**< Ready, after bus reset. */
USB_SELECTED = 3, /**< Address assigned. */
USB_ACTIVE = 4 /**< Active, configuration selected.*/
} usbstate_t;
/**
* @brief Type of an endpoint status.
*/
typedef enum {
EP_STATUS_DISABLED = 0, /**< Endpoint not active. */
EP_STATUS_STALLED = 1, /**< Endpoint opened but stalled. */
EP_STATUS_ACTIVE = 2 /**< Active endpoint. */
} usbepstatus_t;
/**
* @brief Type of an endpoint zero state machine states.
*/
typedef enum {
USB_EP0_WAITING_SETUP, /**< Waiting for SETUP data. */
USB_EP0_TX, /**< Transmitting. */
USB_EP0_WAITING_TX0, /**< Waiting transmit 0. */
USB_EP0_WAITING_STS, /**< Waiting status. */
USB_EP0_RX, /**< Receiving. */
USB_EP0_SENDING_STS, /**< Sending status. */
USB_EP0_ERROR /**< Error, EP0 stalled. */
} usbep0state_t;
/**
* @brief Type of an enumeration of the possible USB events.
*/
typedef enum {
USB_EVENT_RESET = 0, /**< Driver has been reset by host. */
USB_EVENT_ADDRESS = 1, /**< Address assigned. */
USB_EVENT_CONFIGURED = 2, /**< Configuration selected. */
USB_EVENT_SUSPEND = 3, /**< Entering suspend mode. */
USB_EVENT_WAKEUP = 4, /**< Leaving suspend mode. */
USB_EVENT_STALLED = 5 /**< Endpoint 0 error, stalled. */
} usbevent_t;
/**
* @brief Type of an USB descriptor.
*/
typedef struct {
/**
* @brief Descriptor size in unicode characters.
*/
size_t ud_size;
/**
* @brief Pointer to the descriptor.
*/
const uint8_t *ud_string;
} USBDescriptor;
/**
* @brief Type of an USB generic notification callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
*/
typedef void (*usbcallback_t)(USBDriver *usbp);
/**
* @brief Type of an USB endpoint callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @param[in] ep endpoint number
*/
typedef void (*usbepcallback_t)(USBDriver *usbp, usbep_t ep);
/**
* @brief Type of an USB event notification callback.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @param[in] event event type
*/
typedef void (*usbeventcb_t)(USBDriver *usbp, usbevent_t event);
/**
* @brief Type of a requests handler callback.
* @details The request is encoded in the @p usb_setup buffer.
*
* @param[in] usbp pointer to the @p USBDriver object triggering the
* callback
* @return The request handling exit code.
* @retval FALSE Request not recognized by the handler.
* @retval TRUE Request handled.
*/
typedef bool_t (*usbreqhandler_t)(USBDriver *usbp);
/**
* @brief Type of an USB descriptor-retrieving callback.
*/
typedef const USBDescriptor * (*usbgetdescriptor_t)(USBDriver *usbp,
uint8_t dtype,
uint8_t dindex,
uint16_t lang);
#include "usb_lld.h"
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Macro Functions
* @{
*/
/**
* @brief Returns the driver state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The driver state.
*
* @iclass
*/
#define usbGetDriverStateI(usbp) ((usbp)->state)
/**
* @brief Fetches a 16 bits word value from an USB message.
*
* @param[in] p pointer to the 16 bits word
*
* @notapi
*/
#define usbFetchWord(p) ((uint16_t)*(p) | ((uint16_t)*((p) + 1) << 8))
/**
* @brief Connects the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbConnectBus(usbp) usb_lld_connect_bus(usbp)
/**
* @brief Disconnect the USB device.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
#define usbDisconnectBus(usbp) usb_lld_disconnect_bus(usbp)
/**
* @brief Returns the current frame number.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The current frame number.
*
* @api
*/
#define usbGetFrameNumber(usbp) usb_lld_get_frame_number(usbp)
/**
* @brief Returns the status of an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The operation status.
* @retval FALSE Endpoint ready.
* @retval TRUE Endpoint transmitting.
*
* @iclass
*/
#define usbGetTransmitStatusI(usbp, ep) ((usbp)->transmitting & (1 << (ep)))
/**
* @brief Returns the status of an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return The operation status.
* @retval FALSE Endpoint ready.
* @retval TRUE Endpoint receiving.
*
* @iclass
*/
#define usbGetReceiveStatusI(usbp, ep) ((usbp)->receiving & (1 << (ep)))
/**
* @brief Returns the exact size of a receive transaction.
* @details The received size can be different from the size specified in
* @p usbStartReceiveI() because the last packet could have a size
* different from the expected one.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @return Received data size.
*
* @iclass
*/
#define usbGetReceiveTransactionSizeI(usbp, ep) \
usb_lld_get_transaction_size(usbp, ep)
/**
* @brief Request transfer setup.
* @details This macro is used by the request handling callbacks in order to
* prepare a transaction over the endpoint zero.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] buf pointer to a buffer for the transaction data
* @param[in] n number of bytes to be transferred
* @param[in] endcb callback to be invoked after the transfer or @p NULL
*
* @api
*/
#define usbSetupTransfer(usbp, buf, n, endcb) { \
(usbp)->ep0next = (buf); \
(usbp)->ep0n = (n); \
(usbp)->ep0endcb = (endcb); \
}
/**
* @brief Reads a setup packet from the dedicated packet buffer.
* @details This function must be invoked in the context of the @p setup_cb
* callback in order to read the received setup packet.
* @pre In order to use this function the endpoint must have been
* initialized as a control endpoint.
* @note This function can be invoked both in thread and IRQ context.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the packet data
*
* @special
*/
#define usbReadSetup(usbp, ep, buf) usb_lld_read_setup(usbp, ep, buf)
/** @} */
/**
* @name Low Level driver helper macros
* @{
*/
/**
* @brief Common ISR code, usb event callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] evt USB event code
*
* @notapi
*/
#define _usb_isr_invoke_event_cb(usbp, evt) { \
if (((usbp)->config->event_cb) != NULL) \
(usbp)->config->event_cb(usbp, evt); \
}
/**
* @brief Common ISR code, SOF callback.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
#define _usb_isr_invoke_sof_cb(usbp) { \
if (((usbp)->config->sof_cb) != NULL) \
(usbp)->config->sof_cb(usbp); \
}
/**
* @brief Common ISR code, setup packet callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_setup_cb(usbp, ep) { \
(usbp)->epc[ep]->setup_cb(usbp, ep); \
}
/**
* @brief Common ISR code, IN endpoint callback.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_in_cb(usbp, ep) { \
(usbp)->transmitting &= ~(1 << (ep)); \
(usbp)->epc[ep]->in_cb(usbp, ep); \
}
/**
* @brief Common ISR code, OUT endpoint event.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
#define _usb_isr_invoke_out_cb(usbp, ep) { \
(usbp)->receiving &= ~(1 << (ep)); \
(usbp)->epc[ep]->out_cb(usbp, ep); \
}
/** @} */
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void usbInit(void);
void usbObjectInit(USBDriver *usbp);
void usbStart(USBDriver *usbp, const USBConfig *config);
void usbStop(USBDriver *usbp);
void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp);
void usbDisableEndpointsI(USBDriver *usbp);
void usbReadSetupI(USBDriver *usbp, usbep_t ep, uint8_t *buf);
void usbPrepareReceive(USBDriver *usbp, usbep_t ep,
uint8_t *buf, size_t n);
void usbPrepareTransmit(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n);
void usbPrepareQueuedReceive(USBDriver *usbp, usbep_t ep,
input_queue_t *iqp, size_t n);
void usbPrepareQueuedTransmit(USBDriver *usbp, usbep_t ep,
output_queue_t *oqp, size_t n);
bool_t usbStartReceiveI(USBDriver *usbp, usbep_t ep);
bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep);
bool_t usbStallReceiveI(USBDriver *usbp, usbep_t ep);
bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep);
void _usb_reset(USBDriver *usbp);
void _usb_ep0setup(USBDriver *usbp, usbep_t ep);
void _usb_ep0in(USBDriver *usbp, usbep_t ep);
void _usb_ep0out(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_USB */
#endif /* _USB_H_ */
/** @} */

View File

@ -112,7 +112,7 @@ static uint32_t usb_pm_alloc(USBDriver *usbp, size_t size) {
next = usbp->pmnext; next = usbp->pmnext;
usbp->pmnext += size; usbp->pmnext += size;
chDbgAssert(usbp->pmnext <= USB_PMA_SIZE, "usb_pm_alloc(), #1", "PMA overflow"); osalDbgAssert(usbp->pmnext <= USB_PMA_SIZE, "PMA overflow");
return next; return next;
} }
@ -144,14 +144,14 @@ static void usb_packet_read_to_buffer(stm32_usb_descriptor_t *udp,
* @brief Reads from a dedicated packet buffer. * @brief Reads from a dedicated packet buffer.
* *
* @param[in] udp pointer to a @p stm32_usb_descriptor_t * @param[in] udp pointer to a @p stm32_usb_descriptor_t
* @param[in] iqp pointer to an @p InputQueue object * @param[in] iqp pointer to an @p input_queue_t object
* @param[in] n maximum number of bytes to copy. This value must * @param[in] n maximum number of bytes to copy. This value must
* not exceed the maximum packet size for this endpoint. * not exceed the maximum packet size for this endpoint.
* *
* @notapi * @notapi
*/ */
static void usb_packet_read_to_queue(stm32_usb_descriptor_t *udp, static void usb_packet_read_to_queue(stm32_usb_descriptor_t *udp,
InputQueue *iqp, size_t n) { input_queue_t *iqp, size_t n) {
size_t nhw; size_t nhw;
uint32_t *pmap= USB_ADDR2PTR(udp->RXADDR0); uint32_t *pmap= USB_ADDR2PTR(udp->RXADDR0);
@ -176,11 +176,11 @@ static void usb_packet_read_to_queue(stm32_usb_descriptor_t *udp,
} }
/* Updating queue.*/ /* Updating queue.*/
chSysLockFromIsr(); osalSysLockFromISR();
iqp->q_counter += n; iqp->q_counter += n;
while (notempty(&iqp->q_waiting)) while (queue_notempty(&iqp->q_waiting))
chSchReadyI(fifo_remove(&iqp->q_waiting))->p_u.rdymsg = Q_OK; chSchReadyI(queue_fifo_remove(&iqp->q_waiting))->p_u.rdymsg = Q_OK;
chSysUnlockFromIsr(); osalSysUnlockFromISR();
} }
/** /**
@ -220,7 +220,7 @@ static void usb_packet_write_from_buffer(stm32_usb_descriptor_t *udp,
* @notapi * @notapi
*/ */
static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp, static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp,
OutputQueue *oqp, size_t n) { output_queue_t *oqp, size_t n) {
size_t nhw; size_t nhw;
uint32_t *pmap = USB_ADDR2PTR(udp->TXADDR0); uint32_t *pmap = USB_ADDR2PTR(udp->TXADDR0);
@ -250,13 +250,13 @@ static void usb_packet_write_from_queue(stm32_usb_descriptor_t *udp,
function can be called from both ISR and thread context so the kind function can be called from both ISR and thread context so the kind
of lock function to be invoked cannot be decided beforehand.*/ of lock function to be invoked cannot be decided beforehand.*/
port_lock(); port_lock();
dbg_enter_lock(); _dbg_enter_lock();
oqp->q_counter += n; oqp->q_counter += n;
while (notempty(&oqp->q_waiting)) while (queue_notempty(&oqp->q_waiting))
chSchReadyI(fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_OK; chSchReadyI(queue_fifo_remove(&oqp->q_waiting))->p_u.rdymsg = Q_OK;
dbg_leave_lock(); _dbg_leave_lock();
port_unlock(); port_unlock();
} }
@ -366,9 +366,9 @@ CH_IRQ_HANDLER(STM32_USB1_LP_HANDLER) {
epcp->in_state->mode.linear.txbuf, epcp->in_state->mode.linear.txbuf,
n); n);
} }
chSysLockFromIsr(); osalSysLockFromISR();
usb_lld_start_in(usbp, ep); usb_lld_start_in(usbp, ep);
chSysUnlockFromIsr(); osalSysUnlockFromISR();
} }
else { else {
/* Transfer completed, invokes the callback.*/ /* Transfer completed, invokes the callback.*/
@ -456,10 +456,8 @@ void usb_lld_start(USBDriver *usbp) {
STM32_USB->CNTR = CNTR_FRES; STM32_USB->CNTR = CNTR_FRES;
/* Enabling the USB IRQ vectors, this also gives enough time to allow /* Enabling the USB IRQ vectors, this also gives enough time to allow
the transceiver power up (1uS).*/ the transceiver power up (1uS).*/
nvicEnableVector(STM32_USB1_HP_NUMBER, nvicEnableVector(STM32_USB1_HP_NUMBER, STM32_USB_USB1_HP_IRQ_PRIORITY);
CORTEX_PRIORITY_MASK(STM32_USB_USB1_HP_IRQ_PRIORITY)); nvicEnableVector(STM32_USB1_LP_NUMBER, STM32_USB_USB1_LP_IRQ_PRIORITY);
nvicEnableVector(STM32_USB1_LP_NUMBER,
CORTEX_PRIORITY_MASK(STM32_USB_USB1_LP_IRQ_PRIORITY));
/* Releases the USB reset.*/ /* Releases the USB reset.*/
STM32_USB->CNTR = 0; STM32_USB->CNTR = 0;
} }

View File

@ -134,7 +134,7 @@ typedef struct {
/** /**
* @brief Pointer to the output queue. * @brief Pointer to the output queue.
*/ */
OutputQueue *txqueue; output_queue_t *txqueue;
} queue; } queue;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/
} mode; } mode;
@ -167,7 +167,7 @@ typedef struct {
/** /**
* @brief Pointer to the input queue. * @brief Pointer to the input queue.
*/ */
InputQueue *rxqueue; input_queue_t *rxqueue;
} queue; } queue;
} mode; } mode;
/* End of the mandatory fields.*/ /* End of the mandatory fields.*/

View File

@ -13,7 +13,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/common/ARMCMx/nvic.c \
${CHIBIOS}/os/hal/platforms/STM32/TIMv1/pwm_lld.c \ ${CHIBIOS}/os/hal/platforms/STM32/TIMv1/pwm_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/TIMv1/st_lld.c \ ${CHIBIOS}/os/hal/platforms/STM32/TIMv1/st_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/USARTv2/serial_lld.c \ ${CHIBIOS}/os/hal/platforms/STM32/USARTv2/serial_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/USARTv2/uart_lld.c ${CHIBIOS}/os/hal/platforms/STM32/USARTv2/uart_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/USBv1/usb_lld.c
# Required include directories # Required include directories
PLATFORMINC = ${CHIBIOS}/os/hal/platforms/common/ARMCMx \ PLATFORMINC = ${CHIBIOS}/os/hal/platforms/common/ARMCMx \
@ -23,4 +24,5 @@ PLATFORMINC = ${CHIBIOS}/os/hal/platforms/common/ARMCMx \
${CHIBIOS}/os/hal/platforms/STM32/I2Cv2 \ ${CHIBIOS}/os/hal/platforms/STM32/I2Cv2 \
${CHIBIOS}/os/hal/platforms/STM32/SPIv2 \ ${CHIBIOS}/os/hal/platforms/STM32/SPIv2 \
${CHIBIOS}/os/hal/platforms/STM32/TIMv1 \ ${CHIBIOS}/os/hal/platforms/STM32/TIMv1 \
${CHIBIOS}/os/hal/platforms/STM32/USARTv2 ${CHIBIOS}/os/hal/platforms/STM32/USARTv2 \
${CHIBIOS}/os/hal/platforms/STM32/USBv1

411
os/hal/src/serial_usb.c Normal file
View File

@ -0,0 +1,411 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file serial_usb.c
* @brief Serial over USB Driver code.
*
* @addtogroup SERIAL_USB
* @{
*/
#include "hal.h"
#if HAL_USE_SERIAL_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*
* Current Line Coding.
*/
static cdc_linecoding_t linecoding = {
{0x00, 0x96, 0x00, 0x00}, /* 38400. */
LC_STOP_1, LC_PARITY_NONE, 8
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*
* Interface implementation.
*/
static size_t write(void *ip, const uint8_t *bp, size_t n) {
return oqWriteTimeout(&((SerialUSBDriver *)ip)->oqueue, bp,
n, TIME_INFINITE);
}
static size_t read(void *ip, uint8_t *bp, size_t n) {
return iqReadTimeout(&((SerialUSBDriver *)ip)->iqueue, bp,
n, TIME_INFINITE);
}
static msg_t put(void *ip, uint8_t b) {
return oqPutTimeout(&((SerialUSBDriver *)ip)->oqueue, b, TIME_INFINITE);
}
static msg_t get(void *ip) {
return iqGetTimeout(&((SerialUSBDriver *)ip)->iqueue, TIME_INFINITE);
}
static msg_t putt(void *ip, uint8_t b, systime_t timeout) {
return oqPutTimeout(&((SerialUSBDriver *)ip)->oqueue, b, timeout);
}
static msg_t gett(void *ip, systime_t timeout) {
return iqGetTimeout(&((SerialUSBDriver *)ip)->iqueue, timeout);
}
static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t time) {
return oqWriteTimeout(&((SerialUSBDriver *)ip)->oqueue, bp, n, time);
}
static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t time) {
return iqReadTimeout(&((SerialUSBDriver *)ip)->iqueue, bp, n, time);
}
static const struct SerialUSBDriverVMT vmt = {
write, read, put, get,
putt, gett, writet, readt
};
/**
* @brief Notification of data removed from the input queue.
*/
static void inotify(io_queue_t *qp) {
size_t n, maxsize;
SerialUSBDriver *sdup = qGetLink(qp);
/* If the USB driver is not in the appropriate state then transactions
must not be started.*/
if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
(sdup->state != SDU_READY))
return;
/* If there is in the queue enough space to hold at least one packet and
a transaction is not yet started then a new transaction is started for
the available space.*/
maxsize = sdup->config->usbp->epc[sdup->config->bulk_out]->out_maxsize;
if (!usbGetReceiveStatusI(sdup->config->usbp, sdup->config->bulk_out) &&
((n = iqGetEmptyI(&sdup->iqueue)) >= maxsize)) {
osalSysUnlock();
n = (n / maxsize) * maxsize;
usbPrepareQueuedReceive(sdup->config->usbp,
sdup->config->bulk_out,
&sdup->iqueue, n);
osalSysLock();
usbStartReceiveI(sdup->config->usbp, sdup->config->bulk_out);
}
}
/**
* @brief Notification of data inserted into the output queue.
*/
static void onotify(io_queue_t *qp) {
size_t n;
SerialUSBDriver *sdup = qGetLink(qp);
/* If the USB driver is not in the appropriate state then transactions
must not be started.*/
if ((usbGetDriverStateI(sdup->config->usbp) != USB_ACTIVE) ||
(sdup->state != SDU_READY))
return;
/* If there is not an ongoing transaction and the output queue contains
data then a new transaction is started.*/
if (!usbGetTransmitStatusI(sdup->config->usbp, sdup->config->bulk_in) &&
((n = oqGetFullI(&sdup->oqueue)) > 0)) {
osalSysUnlock();
usbPrepareQueuedTransmit(sdup->config->usbp,
sdup->config->bulk_in,
&sdup->oqueue, n);
osalSysLock();
usbStartTransmitI(sdup->config->usbp, sdup->config->bulk_in);
}
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Serial Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void sduInit(void) {
}
/**
* @brief Initializes a generic full duplex driver object.
* @details The HW dependent part of the initialization has to be performed
* outside, usually in the hardware initialization code.
*
* @param[out] sdup pointer to a @p SerialUSBDriver structure
*
* @init
*/
void sduObjectInit(SerialUSBDriver *sdup) {
sdup->vmt = &vmt;
osalEventObjectInit(&sdup->event);
sdup->state = SDU_STOP;
iqObjectInit(&sdup->iqueue, sdup->ib, SERIAL_USB_BUFFERS_SIZE, inotify, sdup);
oqObjectInit(&sdup->oqueue, sdup->ob, SERIAL_USB_BUFFERS_SIZE, onotify, sdup);
}
/**
* @brief Configures and starts the driver.
*
* @param[in] sdup pointer to a @p SerialUSBDriver object
* @param[in] config the serial over USB driver configuration
*
* @api
*/
void sduStart(SerialUSBDriver *sdup, const SerialUSBConfig *config) {
USBDriver *usbp = config->usbp;
osalDbgCheck(sdup != NULL);
osalSysLock();
osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY),
"invalid state");
usbp->in_params[config->bulk_in - 1] = sdup;
usbp->out_params[config->bulk_out - 1] = sdup;
usbp->in_params[config->int_in - 1] = sdup;
sdup->config = config;
sdup->state = SDU_READY;
osalSysUnlock();
}
/**
* @brief Stops the driver.
* @details Any thread waiting on the driver's queues will be awakened with
* the message @p Q_RESET.
*
* @param[in] sdup pointer to a @p SerialUSBDriver object
*
* @api
*/
void sduStop(SerialUSBDriver *sdup) {
USBDriver *usbp = sdup->config->usbp;
osalDbgCheck(sdup != NULL);
osalSysLock();
osalDbgAssert((sdup->state == SDU_STOP) || (sdup->state == SDU_READY),
"invalid state");
/* Driver in stopped state.*/
usbp->in_params[sdup->config->bulk_in - 1] = NULL;
usbp->out_params[sdup->config->bulk_out - 1] = NULL;
usbp->in_params[sdup->config->int_in - 1] = NULL;
sdup->state = SDU_STOP;
/* Queues reset in order to signal the driver stop to the application.*/
chnAddFlagsI(sdup, CHN_DISCONNECTED);
iqResetI(&sdup->iqueue);
iqResetI(&sdup->oqueue);
osalOsRescheduleS();
osalSysUnlock();
}
/**
* @brief USB device configured handler.
*
* @param[in] sdup pointer to a @p SerialUSBDriver object
*
* @iclass
*/
void sduConfigureHookI(SerialUSBDriver *sdup) {
USBDriver *usbp = sdup->config->usbp;
iqResetI(&sdup->iqueue);
oqResetI(&sdup->oqueue);
chnAddFlagsI(sdup, CHN_CONNECTED);
/* Starts the first OUT transaction immediately.*/
usbPrepareQueuedReceive(usbp, sdup->config->bulk_out, &sdup->iqueue,
usbp->epc[sdup->config->bulk_out]->out_maxsize);
usbStartReceiveI(usbp, sdup->config->bulk_out);
}
/**
* @brief Default requests hook.
* @details Applications wanting to use the Serial over USB driver can use
* this function as requests hook in the USB configuration.
* The following requests are emulated:
* - CDC_GET_LINE_CODING.
* - CDC_SET_LINE_CODING.
* - CDC_SET_CONTROL_LINE_STATE.
* .
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The hook status.
* @retval TRUE Message handled internally.
* @retval FALSE Message not handled.
*/
bool_t sduRequestsHook(USBDriver *usbp) {
if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) {
switch (usbp->setup[1]) {
case CDC_GET_LINE_CODING:
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
return TRUE;
case CDC_SET_LINE_CODING:
usbSetupTransfer(usbp, (uint8_t *)&linecoding, sizeof(linecoding), NULL);
return TRUE;
case CDC_SET_CONTROL_LINE_STATE:
/* Nothing to do, there are no control lines.*/
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
default:
return FALSE;
}
}
return FALSE;
}
/**
* @brief Default data transmitted callback.
* @details The application must use this function as callback for the IN
* data endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*/
void sduDataTransmitted(USBDriver *usbp, usbep_t ep) {
size_t n;
SerialUSBDriver *sdup = usbp->in_params[ep - 1];
if (sdup == NULL)
return;
osalSysLockFromISR();
chnAddFlagsI(sdup, CHN_OUTPUT_EMPTY);
if ((n = oqGetFullI(&sdup->oqueue)) > 0) {
/* The endpoint cannot be busy, we are in the context of the callback,
so it is safe to transmit without a check.*/
osalSysUnlockFromISR();
usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, n);
osalSysLockFromISR();
usbStartTransmitI(usbp, ep);
}
else if ((usbp->epc[ep]->in_state->txsize > 0) &&
!(usbp->epc[ep]->in_state->txsize &
(usbp->epc[ep]->in_maxsize - 1))) {
/* Transmit zero sized packet in case the last one has maximum allowed
size. Otherwise the recipient may expect more data coming soon and
not return buffered data to app. See section 5.8.3 Bulk Transfer
Packet Size Constraints of the USB Specification document.*/
osalSysUnlockFromISR();
usbPrepareQueuedTransmit(usbp, ep, &sdup->oqueue, 0);
osalSysLockFromISR();
usbStartTransmitI(usbp, ep);
}
osalSysUnlockFromISR();
}
/**
* @brief Default data received callback.
* @details The application must use this function as callback for the OUT
* data endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*/
void sduDataReceived(USBDriver *usbp, usbep_t ep) {
size_t n, maxsize;
SerialUSBDriver *sdup = usbp->out_params[ep - 1];
if (sdup == NULL)
return;
osalSysLockFromISR();
chnAddFlagsI(sdup, CHN_INPUT_AVAILABLE);
/* Writes to the input queue can only happen when there is enough space
to hold at least one packet.*/
maxsize = usbp->epc[ep]->out_maxsize;
if ((n = iqGetEmptyI(&sdup->iqueue)) >= maxsize) {
/* The endpoint cannot be busy, we are in the context of the callback,
so a packet is in the buffer for sure.*/
osalSysUnlockFromISR();
n = (n / maxsize) * maxsize;
usbPrepareQueuedReceive(usbp, ep, &sdup->iqueue, n);
osalSysLockFromISR();
usbStartReceiveI(usbp, ep);
}
osalSysUnlockFromISR();
}
/**
* @brief Default data received callback.
* @details The application must use this function as callback for the IN
* interrupt endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*/
void sduInterruptTransmitted(USBDriver *usbp, usbep_t ep) {
(void)usbp;
(void)ep;
}
#endif /* HAL_USE_SERIAL */
/** @} */

776
os/hal/src/usb.c Normal file
View File

@ -0,0 +1,776 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
ChibiOS/RT is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
ChibiOS/RT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* @file usb.c
* @brief USB Driver code.
*
* @addtogroup USB
* @{
*/
#include <string.h>
#include "hal.h"
#if HAL_USE_USB || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
static const uint8_t zero_status[] = {0x00, 0x00};
static const uint8_t active_status[] ={0x00, 0x00};
static const uint8_t halted_status[] = {0x01, 0x00};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief SET ADDRESS transaction callback.
*
* @param[in] usbp pointer to the @p USBDriver object
*/
static void set_address(USBDriver *usbp) {
usbp->address = usbp->setup[2];
usb_lld_set_address(usbp);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_ADDRESS);
usbp->state = USB_SELECTED;
}
/**
* @brief Standard requests handler.
* @details This is the standard requests default handler, most standard
* requests are handled here, the user can override the standard
* handling using the @p requests_hook_cb hook in the
* @p USBConfig structure.
*
* @param[in] usbp pointer to the @p USBDriver object
* @return The request handling exit code.
* @retval FALSE Request not recognized by the handler or error.
* @retval TRUE Request handled.
*/
static bool_t default_handler(USBDriver *usbp) {
const USBDescriptor *dp;
/* Decoding the request.*/
switch (((usbp->setup[0] & (USB_RTYPE_RECIPIENT_MASK |
USB_RTYPE_TYPE_MASK)) |
(usbp->setup[1] << 8))) {
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_STATUS << 8):
/* Just returns the current status word.*/
usbSetupTransfer(usbp, (uint8_t *)&usbp->status, 2, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_CLEAR_FEATURE << 8):
/* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature
number is handled as an error.*/
if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
usbp->status &= ~2;
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
}
return FALSE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_FEATURE << 8):
/* Only the DEVICE_REMOTE_WAKEUP is handled here, any other feature
number is handled as an error.*/
if (usbp->setup[2] == USB_FEATURE_DEVICE_REMOTE_WAKEUP) {
usbp->status |= 2;
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
}
return FALSE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_ADDRESS << 8):
/* The SET_ADDRESS handling can be performed here or postponed after
the status packed depending on the USB_SET_ADDRESS_MODE low
driver setting.*/
#if USB_SET_ADDRESS_MODE == USB_EARLY_SET_ADDRESS
if ((usbp->setup[0] == USB_RTYPE_RECIPIENT_DEVICE) &&
(usbp->setup[1] == USB_REQ_SET_ADDRESS))
set_address(usbp);
usbSetupTransfer(usbp, NULL, 0, NULL);
#else
usbSetupTransfer(usbp, NULL, 0, set_address);
#endif
return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_DESCRIPTOR << 8):
/* Handling descriptor requests from the host.*/
dp = usbp->config->get_descriptor_cb(
usbp, usbp->setup[3], usbp->setup[2],
usbFetchWord(&usbp->setup[4]));
if (dp == NULL)
return FALSE;
usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_GET_CONFIGURATION << 8):
/* Returning the last selected configuration.*/
usbSetupTransfer(usbp, &usbp->configuration, 1, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_CONFIGURATION << 8):
/* Handling configuration selection from the host.*/
usbp->configuration = usbp->setup[2];
if (usbp->configuration == 0)
usbp->state = USB_SELECTED;
else
usbp->state = USB_ACTIVE;
_usb_isr_invoke_event_cb(usbp, USB_EVENT_CONFIGURED);
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_STATUS << 8):
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SYNCH_FRAME << 8):
/* Just sending two zero bytes, the application can change the behavior
using a hook..*/
usbSetupTransfer(usbp, (uint8_t *)zero_status, 2, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_GET_STATUS << 8):
/* Sending the EP status.*/
if (usbp->setup[4] & 0x80) {
switch (usb_lld_get_status_in(usbp, usbp->setup[4] & 0x0F)) {
case EP_STATUS_STALLED:
usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
return TRUE;
case EP_STATUS_ACTIVE:
usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
return TRUE;
default:
return FALSE;
}
}
else {
switch (usb_lld_get_status_out(usbp, usbp->setup[4] & 0x0F)) {
case EP_STATUS_STALLED:
usbSetupTransfer(usbp, (uint8_t *)halted_status, 2, NULL);
return TRUE;
case EP_STATUS_ACTIVE:
usbSetupTransfer(usbp, (uint8_t *)active_status, 2, NULL);
return TRUE;
default:
return FALSE;
}
}
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_CLEAR_FEATURE << 8):
/* Only ENDPOINT_HALT is handled as feature.*/
if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT)
return FALSE;
/* Clearing the EP status, not valid for EP0, it is ignored in that case.*/
if ((usbp->setup[4] & 0x0F) > 0) {
if (usbp->setup[4] & 0x80)
usb_lld_clear_in(usbp, usbp->setup[4] & 0x0F);
else
usb_lld_clear_out(usbp, usbp->setup[4] & 0x0F);
}
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_ENDPOINT | (USB_REQ_SET_FEATURE << 8):
/* Only ENDPOINT_HALT is handled as feature.*/
if (usbp->setup[2] != USB_FEATURE_ENDPOINT_HALT)
return FALSE;
/* Stalling the EP, not valid for EP0, it is ignored in that case.*/
if ((usbp->setup[4] & 0x0F) > 0) {
if (usbp->setup[4] & 0x80)
usb_lld_stall_in(usbp, usbp->setup[4] & 0x0F);
else
usb_lld_stall_out(usbp, usbp->setup[4] & 0x0F);
}
usbSetupTransfer(usbp, NULL, 0, NULL);
return TRUE;
case USB_RTYPE_RECIPIENT_DEVICE | (USB_REQ_SET_DESCRIPTOR << 8):
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_CLEAR_FEATURE << 8):
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_SET_FEATURE << 8):
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_GET_INTERFACE << 8):
case USB_RTYPE_RECIPIENT_INTERFACE | (USB_REQ_SET_INTERFACE << 8):
/* All the above requests are not handled here, if you need them then
use the hook mechanism and provide handling.*/
default:
return FALSE;
}
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief USB Driver initialization.
* @note This function is implicitly invoked by @p halInit(), there is
* no need to explicitly initialize the driver.
*
* @init
*/
void usbInit(void) {
usb_lld_init();
}
/**
* @brief Initializes the standard part of a @p USBDriver structure.
*
* @param[out] usbp pointer to the @p USBDriver object
*
* @init
*/
void usbObjectInit(USBDriver *usbp) {
unsigned i;
usbp->state = USB_STOP;
usbp->config = NULL;
for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
usbp->in_params[i] = NULL;
usbp->out_params[i] = NULL;
}
usbp->transmitting = 0;
usbp->receiving = 0;
}
/**
* @brief Configures and activates the USB peripheral.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] config pointer to the @p USBConfig object
*
* @api
*/
void usbStart(USBDriver *usbp, const USBConfig *config) {
unsigned i;
osalDbgCheck((usbp != NULL) && (config != NULL));
osalSysLock();
osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY),
"invalid state");
usbp->config = config;
for (i = 0; i <= USB_MAX_ENDPOINTS; i++)
usbp->epc[i] = NULL;
usb_lld_start(usbp);
usbp->state = USB_READY;
osalSysUnlock();
}
/**
* @brief Deactivates the USB peripheral.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @api
*/
void usbStop(USBDriver *usbp) {
osalDbgCheck(usbp != NULL);
osalSysLock();
osalDbgAssert((usbp->state == USB_STOP) || (usbp->state == USB_READY) ||
(usbp->state == USB_SELECTED) || (usbp->state == USB_ACTIVE),
"invalid state");
usb_lld_stop(usbp);
usbp->state = USB_STOP;
osalSysUnlock();
}
/**
* @brief Enables an endpoint.
* @details This function enables an endpoint, both IN and/or OUT directions
* depending on the configuration structure.
* @note This function must be invoked in response of a SET_CONFIGURATION
* or SET_INTERFACE message.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] epcp the endpoint configuration
*
* @iclass
*/
void usbInitEndpointI(USBDriver *usbp, usbep_t ep,
const USBEndpointConfig *epcp) {
osalDbgCheckClassI();
osalDbgCheck((usbp != NULL) && (epcp != NULL));
osalDbgAssert(usbp->state == USB_ACTIVE,
"invalid state");
osalDbgAssert(usbp->epc[ep] == NULL, "already initialized");
/* Logically enabling the endpoint in the USBDriver structure.*/
if (epcp->in_state != NULL)
memset(epcp->in_state, 0, sizeof(USBInEndpointState));
if (epcp->out_state != NULL)
memset(epcp->out_state, 0, sizeof(USBOutEndpointState));
usbp->epc[ep] = epcp;
/* Low level endpoint activation.*/
usb_lld_init_endpoint(usbp, ep);
}
/**
* @brief Disables all the active endpoints.
* @details This function disables all the active endpoints except the
* endpoint zero.
* @note This function must be invoked in response of a SET_CONFIGURATION
* message with configuration number zero.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @iclass
*/
void usbDisableEndpointsI(USBDriver *usbp) {
unsigned i;
osalDbgCheckClassI();
osalDbgCheck(usbp != NULL);
osalDbgAssert(usbp->state == USB_SELECTED, "invalid state");
usbp->transmitting &= ~1;
usbp->receiving &= ~1;
for (i = 1; i <= USB_MAX_ENDPOINTS; i++)
usbp->epc[i] = NULL;
/* Low level endpoints deactivation.*/
usb_lld_disable_endpoints(usbp);
}
/**
* @brief Prepares for a receive transaction on an OUT endpoint.
* @post The endpoint is ready for @p usbStartReceiveI().
* @note This function can be called both in ISR and thread context.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[out] buf buffer where to copy the received data
* @param[in] n transaction size
*
* @special
*/
void usbPrepareReceive(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
osp->rxqueued = FALSE;
osp->mode.linear.rxbuf = buf;
osp->rxsize = n;
osp->rxcnt = 0;
usb_lld_prepare_receive(usbp, ep);
}
/**
* @brief Prepares for a transmit transaction on an IN endpoint.
* @post The endpoint is ready for @p usbStartTransmitI().
* @note This function can be called both in ISR and thread context.
* @note The queue must contain at least the amount of data specified
* as transaction size.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] buf buffer where to fetch the data to be transmitted
* @param[in] n transaction size
*
* @special
*/
void usbPrepareTransmit(USBDriver *usbp, usbep_t ep,
const uint8_t *buf, size_t n) {
USBInEndpointState *isp = usbp->epc[ep]->in_state;
isp->txqueued = FALSE;
isp->mode.linear.txbuf = buf;
isp->txsize = n;
isp->txcnt = 0;
usb_lld_prepare_transmit(usbp, ep);
}
/**
* @brief Prepares for a receive transaction on an OUT endpoint.
* @post The endpoint is ready for @p usbStartReceiveI().
* @note This function can be called both in ISR and thread context.
* @note The queue must have enough free space to accommodate the
* specified transaction size rounded to the next packet size
* boundary. For example if the transaction size is 1 and the
* packet size is 64 then the queue must have space for at least
* 64 bytes.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] iqp input queue to be filled with incoming data
* @param[in] n transaction size
*
* @special
*/
void usbPrepareQueuedReceive(USBDriver *usbp, usbep_t ep,
input_queue_t *iqp, size_t n) {
USBOutEndpointState *osp = usbp->epc[ep]->out_state;
osp->rxqueued = TRUE;
osp->mode.queue.rxqueue = iqp;
osp->rxsize = n;
osp->rxcnt = 0;
usb_lld_prepare_receive(usbp, ep);
}
/**
* @brief Prepares for a transmit transaction on an IN endpoint.
* @post The endpoint is ready for @p usbStartTransmitI().
* @note This function can be called both in ISR and thread context.
* @note The transmit transaction size is equal to the data contained
* in the queue.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
* @param[in] oqp output queue to be fetched for outgoing data
* @param[in] n transaction size
*
* @special
*/
void usbPrepareQueuedTransmit(USBDriver *usbp, usbep_t ep,
output_queue_t *oqp, size_t n) {
USBInEndpointState *isp = usbp->epc[ep]->in_state;
isp->txqueued = TRUE;
isp->mode.queue.txqueue = oqp;
isp->txsize = n;
isp->txcnt = 0;
usb_lld_prepare_transmit(usbp, ep);
}
/**
* @brief Starts a receive transaction on an OUT endpoint.
* @post The endpoint callback is invoked when the transfer has been
* completed.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval FALSE Operation started successfully.
* @retval TRUE Endpoint busy, operation not started.
*
* @iclass
*/
bool_t usbStartReceiveI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck(usbp != NULL);
if (usbGetReceiveStatusI(usbp, ep))
return TRUE;
usbp->receiving |= (1 << ep);
usb_lld_start_out(usbp, ep);
return FALSE;
}
/**
* @brief Starts a transmit transaction on an IN endpoint.
* @post The endpoint callback is invoked when the transfer has been
* completed.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval FALSE Operation started successfully.
* @retval TRUE Endpoint busy, operation not started.
*
* @iclass
*/
bool_t usbStartTransmitI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck(usbp != NULL);
if (usbGetTransmitStatusI(usbp, ep))
return TRUE;
usbp->transmitting |= (1 << ep);
usb_lld_start_in(usbp, ep);
return FALSE;
}
/**
* @brief Stalls an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval FALSE Endpoint stalled.
* @retval TRUE Endpoint busy, not stalled.
*
* @iclass
*/
bool_t usbStallReceiveI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck(usbp != NULL);
if (usbGetReceiveStatusI(usbp, ep))
return TRUE;
usb_lld_stall_out(usbp, ep);
return FALSE;
}
/**
* @brief Stalls an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @return The operation status.
* @retval FALSE Endpoint stalled.
* @retval TRUE Endpoint busy, not stalled.
*
* @iclass
*/
bool_t usbStallTransmitI(USBDriver *usbp, usbep_t ep) {
osalDbgCheckClassI();
osalDbgCheck(usbp != NULL);
if (usbGetTransmitStatusI(usbp, ep))
return TRUE;
usb_lld_stall_in(usbp, ep);
return FALSE;
}
/**
* @brief USB reset routine.
* @details This function must be invoked when an USB bus reset condition is
* detected.
*
* @param[in] usbp pointer to the @p USBDriver object
*
* @notapi
*/
void _usb_reset(USBDriver *usbp) {
unsigned i;
usbp->state = USB_READY;
usbp->status = 0;
usbp->address = 0;
usbp->configuration = 0;
usbp->transmitting = 0;
usbp->receiving = 0;
/* Invalidates all endpoints into the USBDriver structure.*/
for (i = 0; i <= USB_MAX_ENDPOINTS; i++)
usbp->epc[i] = NULL;
/* EP0 state machine initialization.*/
usbp->ep0state = USB_EP0_WAITING_SETUP;
/* Low level reset.*/
usb_lld_reset(usbp);
}
/**
* @brief Default EP0 SETUP callback.
* @details This function is used by the low level driver as default handler
* for EP0 SETUP events.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number, always zero
*
* @notapi
*/
void _usb_ep0setup(USBDriver *usbp, usbep_t ep) {
size_t max;
usbp->ep0state = USB_EP0_WAITING_SETUP;
usbReadSetup(usbp, ep, usbp->setup);
/* First verify if the application has an handler installed for this
request.*/
if (!(usbp->config->requests_hook_cb) ||
!(usbp->config->requests_hook_cb(usbp))) {
/* Invoking the default handler, if this fails then stalls the
endpoint zero as error.*/
if (((usbp->setup[0] & USB_RTYPE_TYPE_MASK) != USB_RTYPE_TYPE_STD) ||
!default_handler(usbp)) {
/* Error response, the state machine goes into an error state, the low
level layer will have to reset it to USB_EP0_WAITING_SETUP after
receiving a SETUP packet.*/
usb_lld_stall_in(usbp, 0);
usb_lld_stall_out(usbp, 0);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
return;
}
}
/* Transfer preparation. The request handler must have populated
correctly the fields ep0next, ep0n and ep0endcb using the macro
usbSetupTransfer().*/
max = usbFetchWord(&usbp->setup[6]);
/* The transfer size cannot exceed the specified amount.*/
if (usbp->ep0n > max)
usbp->ep0n = max;
if ((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) {
/* IN phase.*/
if (usbp->ep0n > 0) {
/* Starts the transmit phase.*/
usbp->ep0state = USB_EP0_TX;
usbPrepareTransmit(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysLockFromISR();
usbStartTransmitI(usbp, 0);
osalSysUnlockFromISR();
}
else {
/* No transmission phase, directly receiving the zero sized status
packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
usbPrepareReceive(usbp, 0, NULL, 0);
osalSysLockFromISR();
usbStartReceiveI(usbp, 0);
osalSysUnlockFromISR();
}
}
else {
/* OUT phase.*/
if (usbp->ep0n > 0) {
/* Starts the receive phase.*/
usbp->ep0state = USB_EP0_RX;
usbPrepareReceive(usbp, 0, usbp->ep0next, usbp->ep0n);
osalSysLockFromISR();
usbStartReceiveI(usbp, 0);
osalSysUnlockFromISR();
}
else {
/* No receive phase, directly sending the zero sized status
packet.*/
usbp->ep0state = USB_EP0_SENDING_STS;
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR();
usbStartTransmitI(usbp, 0);
osalSysUnlockFromISR();
}
}
}
/**
* @brief Default EP0 IN callback.
* @details This function is used by the low level driver as default handler
* for EP0 IN events.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number, always zero
*
* @notapi
*/
void _usb_ep0in(USBDriver *usbp, usbep_t ep) {
size_t max;
(void)ep;
switch (usbp->ep0state) {
case USB_EP0_TX:
max = usbFetchWord(&usbp->setup[6]);
/* If the transmitted size is less than the requested size and it is a
multiple of the maximum packet size then a zero size packet must be
transmitted.*/
if ((usbp->ep0n < max) && ((usbp->ep0n % usbp->epc[0]->in_maxsize) == 0)) {
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR();
usbStartTransmitI(usbp, 0);
osalSysUnlockFromISR();
usbp->ep0state = USB_EP0_WAITING_TX0;
return;
}
/* Falls into, it is intentional.*/
case USB_EP0_WAITING_TX0:
/* Transmit phase over, receiving the zero sized status packet.*/
usbp->ep0state = USB_EP0_WAITING_STS;
usbPrepareReceive(usbp, 0, NULL, 0);
osalSysLockFromISR();
usbStartReceiveI(usbp, 0);
osalSysUnlockFromISR();
return;
case USB_EP0_SENDING_STS:
/* Status packet sent, invoking the callback if defined.*/
if (usbp->ep0endcb != NULL)
usbp->ep0endcb(usbp);
usbp->ep0state = USB_EP0_WAITING_SETUP;
return;
default:
;
}
/* Error response, the state machine goes into an error state, the low
level layer will have to reset it to USB_EP0_WAITING_SETUP after
receiving a SETUP packet.*/
usb_lld_stall_in(usbp, 0);
usb_lld_stall_out(usbp, 0);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
}
/**
* @brief Default EP0 OUT callback.
* @details This function is used by the low level driver as default handler
* for EP0 OUT events.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number, always zero
*
* @notapi
*/
void _usb_ep0out(USBDriver *usbp, usbep_t ep) {
(void)ep;
switch (usbp->ep0state) {
case USB_EP0_RX:
/* Receive phase over, sending the zero sized status packet.*/
usbp->ep0state = USB_EP0_SENDING_STS;
usbPrepareTransmit(usbp, 0, NULL, 0);
osalSysLockFromISR();
usbStartTransmitI(usbp, 0);
osalSysUnlockFromISR();
return;
case USB_EP0_WAITING_STS:
/* Status packet received, it must be zero sized, invoking the callback
if defined.*/
if (usbGetReceiveTransactionSizeI(usbp, 0) != 0)
break;
if (usbp->ep0endcb != NULL)
usbp->ep0endcb(usbp);
usbp->ep0state = USB_EP0_WAITING_SETUP;
return;
default:
;
}
/* Error response, the state machine goes into an error state, the low
level layer will have to reset it to USB_EP0_WAITING_SETUP after
receiving a SETUP packet.*/
usb_lld_stall_in(usbp, 0);
usb_lld_stall_out(usbp, 0);
_usb_isr_invoke_event_cb(usbp, USB_EVENT_STALLED);
usbp->ep0state = USB_EP0_ERROR;
}
#endif /* HAL_USE_USB */
/** @} */

View File

@ -32,7 +32,7 @@
/** /**
* @brief Shell termination event source. * @brief Shell termination event source.
*/ */
EventSource shell_terminated; event_source_t shell_terminated;
static char *_strtok(char *str, const char *delim, char **saveptr) { static char *_strtok(char *str, const char *delim, char **saveptr) {
char *token; char *token;
@ -133,12 +133,12 @@ static bool_t cmdexec(const ShellCommand *scp, BaseSequentialStream *chp,
* *
* @param[in] p pointer to a @p BaseSequentialStream object * @param[in] p pointer to a @p BaseSequentialStream object
* @return Termination reason. * @return Termination reason.
* @retval RDY_OK terminated by command. * @retval MSG_OK terminated by command.
* @retval RDY_RESET terminated by reset condition on the I/O channel. * @retval MSG_RESET terminated by reset condition on the I/O channel.
*/ */
static msg_t shell_thread(void *p) { static msg_t shell_thread(void *p) {
int n; int n;
msg_t msg = RDY_OK; msg_t msg = MSG_OK;
BaseSequentialStream *chp = ((ShellConfig *)p)->sc_channel; BaseSequentialStream *chp = ((ShellConfig *)p)->sc_channel;
const ShellCommand *scp = ((ShellConfig *)p)->sc_commands; const ShellCommand *scp = ((ShellConfig *)p)->sc_commands;
char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH]; char *lp, *cmd, *tokp, line[SHELL_MAX_LINE_LENGTH];
@ -203,12 +203,12 @@ static msg_t shell_thread(void *p) {
*/ */
void shellInit(void) { void shellInit(void) {
chEvtInit(&shell_terminated); chEvtObjectInit(&shell_terminated);
} }
/** /**
* @brief Spawns a new shell. * @brief Spawns a new shell.
* @pre @p CH_USE_MALLOC_HEAP and @p CH_USE_DYNAMIC must be enabled. * @pre @p CH_CFG_USE_HEAP and @p CH_CFG_USE_DYNAMIC must be enabled.
* *
* @param[in] scp pointer to a @p ShellConfig object * @param[in] scp pointer to a @p ShellConfig object
* @param[in] size size of the shell working area to be allocated * @param[in] size size of the shell working area to be allocated
@ -216,8 +216,8 @@ void shellInit(void) {
* @return A pointer to the shell thread. * @return A pointer to the shell thread.
* @retval NULL thread creation failed because memory allocation. * @retval NULL thread creation failed because memory allocation.
*/ */
#if CH_USE_HEAP && CH_USE_DYNAMIC #if CH_CFG_USE_HEAP && CH_CFG_USE_DYNAMIC
Thread *shellCreate(const ShellConfig *scp, size_t size, tprio_t prio) { thread_t *shellCreate(const ShellConfig *scp, size_t size, tprio_t prio) {
return chThdCreateFromHeap(NULL, size, prio, shell_thread, (void *)scp); return chThdCreateFromHeap(NULL, size, prio, shell_thread, (void *)scp);
} }
@ -232,7 +232,7 @@ Thread *shellCreate(const ShellConfig *scp, size_t size, tprio_t prio) {
* @param[in] prio priority level for the new shell * @param[in] prio priority level for the new shell
* @return A pointer to the shell thread. * @return A pointer to the shell thread.
*/ */
Thread *shellCreateStatic(const ShellConfig *scp, void *wsp, thread_t *shellCreateStatic(const ShellConfig *scp, void *wsp,
size_t size, tprio_t prio) { size_t size, tprio_t prio) {
return chThdCreateStatic(wsp, size, prio, shell_thread, (void *)scp); return chThdCreateStatic(wsp, size, prio, shell_thread, (void *)scp);

View File

@ -27,7 +27,7 @@
<link> <link>
<name>board</name> <name>board</name>
<type>2</type> <type>2</type>
<locationURI>CHIBIOS/boards/ST_STM32F3_DISCOVERY</locationURI> <locationURI>CHIBIOS/os/hal/boards/ST_STM32F3_DISCOVERY</locationURI>
</link> </link>
<link> <link>
<name>os</name> <name>os</name>

View File

@ -292,7 +292,7 @@ static void usb_event(USBDriver *usbp, usbevent_t event) {
case USB_EVENT_ADDRESS: case USB_EVENT_ADDRESS:
return; return;
case USB_EVENT_CONFIGURED: case USB_EVENT_CONFIGURED:
chSysLockFromIsr(); chSysLockFromISR();
/* Enables the endpoints specified into the configuration. /* Enables the endpoints specified into the configuration.
Note, this callback is invoked from an ISR so I-Class functions Note, this callback is invoked from an ISR so I-Class functions
@ -303,7 +303,7 @@ static void usb_event(USBDriver *usbp, usbevent_t event) {
/* Resetting the state of the CDC subsystem.*/ /* Resetting the state of the CDC subsystem.*/
sduConfigureHookI(&SDU1); sduConfigureHookI(&SDU1);
chSysUnlockFromIsr(); chSysUnlockFromISR();
return; return;
case USB_EVENT_SUSPEND: case USB_EVENT_SUSPEND:
return; return;
@ -357,34 +357,34 @@ static void cmd_mem(BaseSequentialStream *chp, int argc, char *argv[]) {
} }
static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) { static void cmd_threads(BaseSequentialStream *chp, int argc, char *argv[]) {
static const char *states[] = {THD_STATE_NAMES}; static const char *states[] = {CH_STATE_NAMES};
Thread *tp; thread_t *tp;
(void)argv; (void)argv;
if (argc > 0) { if (argc > 0) {
chprintf(chp, "Usage: threads\r\n"); chprintf(chp, "Usage: threads\r\n");
return; return;
} }
chprintf(chp, " addr stack prio refs state time\r\n"); chprintf(chp, " addr stack prio refs state\r\n");
tp = chRegFirstThread(); tp = chRegFirstThread();
do { do {
chprintf(chp, "%.8lx %.8lx %4lu %4lu %9s %lu\r\n", chprintf(chp, "%.8lx %.8lx %4lu %4lu %9s %lu\r\n",
(uint32_t)tp, (uint32_t)tp->p_ctx.r13, (uint32_t)tp, (uint32_t)tp->p_ctx.r13,
(uint32_t)tp->p_prio, (uint32_t)(tp->p_refs - 1), (uint32_t)tp->p_prio, (uint32_t)(tp->p_refs - 1),
states[tp->p_state], (uint32_t)tp->p_time); states[tp->p_state]);
tp = chRegNextThread(tp); tp = chRegNextThread(tp);
} while (tp != NULL); } while (tp != NULL);
} }
static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) { static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) {
Thread *tp; thread_t *tp;
(void)argv; (void)argv;
if (argc > 0) { if (argc > 0) {
chprintf(chp, "Usage: test\r\n"); chprintf(chp, "Usage: test\r\n");
return; return;
} }
tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriority(), tp = chThdCreateFromHeap(NULL, TEST_WA_SIZE, chThdGetPriorityX(),
TestThread, chp); TestThread, chp);
if (tp == NULL) { if (tp == NULL) {
chprintf(chp, "out of memory\r\n"); chprintf(chp, "out of memory\r\n");
@ -462,7 +462,7 @@ static msg_t Thread1(void *arg) {
* Application entry point. * Application entry point.
*/ */
int main(void) { int main(void) {
Thread *shelltp = NULL; thread_t *shelltp = NULL;
/* /*
* System initializations. * System initializations.
@ -507,7 +507,7 @@ int main(void) {
while (TRUE) { while (TRUE) {
if (!shelltp && (SDU1.config->usbp->state == USB_ACTIVE)) if (!shelltp && (SDU1.config->usbp->state == USB_ACTIVE))
shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO); shelltp = shellCreate(&shell_cfg1, SHELL_WA_SIZE, NORMALPRIO);
else if (chThdTerminated(shelltp)) { else if (chThdTerminatedX(shelltp)) {
chThdRelease(shelltp); /* Recovers memory of the previous shell. */ chThdRelease(shelltp); /* Recovers memory of the previous shell. */
shelltp = NULL; /* Triggers spawning of a new shell. */ shelltp = NULL; /* Triggers spawning of a new shell. */
} }

View File

@ -179,9 +179,9 @@
/* /*
* SPI driver system settings. * SPI driver system settings.
*/ */
#define STM32_SPI_USE_SPI1 TRUE #define STM32_SPI_USE_SPI1 FALSE
#define STM32_SPI_USE_SPI2 TRUE #define STM32_SPI_USE_SPI2 FALSE
#define STM32_SPI_USE_SPI3 TRUE #define STM32_SPI_USE_SPI3 FALSE
#define STM32_SPI_SPI1_DMA_PRIORITY 1 #define STM32_SPI_SPI1_DMA_PRIORITY 1
#define STM32_SPI_SPI2_DMA_PRIORITY 1 #define STM32_SPI_SPI2_DMA_PRIORITY 1
#define STM32_SPI_SPI3_DMA_PRIORITY 1 #define STM32_SPI_SPI3_DMA_PRIORITY 1