/* ChibiOS - Copyright (C) 2006..2018 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. */ /* Parts of this file have been contributed by Matthias Blaicher. */ /** * @file hal_mmc_spi.c * @brief MMC over SPI driver code. * * @addtogroup MMC_SPI * @{ */ #include #include "hal.h" #if (HAL_USE_MMC_SPI == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local variables and types. */ /*===========================================================================*/ /* Forward declarations required by mmc_vmt.*/ static bool mmc_read(void *instance, uint32_t startblk, uint8_t *buffer, uint32_t n); static bool mmc_write(void *instance, uint32_t startblk, const uint8_t *buffer, uint32_t n); /** * @brief Virtual methods table. */ static const struct MMCDriverVMT mmc_vmt = { (size_t)0, (bool (*)(void *))mmc_lld_is_card_inserted, (bool (*)(void *))mmc_lld_is_write_protected, (bool (*)(void *))mmcConnect, (bool (*)(void *))mmcDisconnect, mmc_read, mmc_write, (bool (*)(void *))mmcSync, (bool (*)(void *, BlockDeviceInfo *))mmcGetInfo }; /** * @brief Lookup table for CRC-7 ( based on polynomial x^7 + x^3 + 1). */ static const uint8_t crc7_lookup_table[256] = { 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, 0x19, 0x10, 0x0b, 0x02, 0x3d, 0x34, 0x2f, 0x26, 0x51, 0x58, 0x43, 0x4a, 0x75, 0x7c, 0x67, 0x6e, 0x32, 0x3b, 0x20, 0x29, 0x16, 0x1f, 0x04, 0x0d, 0x7a, 0x73, 0x68, 0x61, 0x5e, 0x57, 0x4c, 0x45, 0x2b, 0x22, 0x39, 0x30, 0x0f, 0x06, 0x1d, 0x14, 0x63, 0x6a, 0x71, 0x78, 0x47, 0x4e, 0x55, 0x5c, 0x64, 0x6d, 0x76, 0x7f, 0x40, 0x49, 0x52, 0x5b, 0x2c, 0x25, 0x3e, 0x37, 0x08, 0x01, 0x1a, 0x13, 0x7d, 0x74, 0x6f, 0x66, 0x59, 0x50, 0x4b, 0x42, 0x35, 0x3c, 0x27, 0x2e, 0x11, 0x18, 0x03, 0x0a, 0x56, 0x5f, 0x44, 0x4d, 0x72, 0x7b, 0x60, 0x69, 0x1e, 0x17, 0x0c, 0x05, 0x3a, 0x33, 0x28, 0x21, 0x4f, 0x46, 0x5d, 0x54, 0x6b, 0x62, 0x79, 0x70, 0x07, 0x0e, 0x15, 0x1c, 0x23, 0x2a, 0x31, 0x38, 0x41, 0x48, 0x53, 0x5a, 0x65, 0x6c, 0x77, 0x7e, 0x09, 0x00, 0x1b, 0x12, 0x2d, 0x24, 0x3f, 0x36, 0x58, 0x51, 0x4a, 0x43, 0x7c, 0x75, 0x6e, 0x67, 0x10, 0x19, 0x02, 0x0b, 0x34, 0x3d, 0x26, 0x2f, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x6a, 0x63, 0x78, 0x71, 0x4e, 0x47, 0x5c, 0x55, 0x22, 0x2b, 0x30, 0x39, 0x06, 0x0f, 0x14, 0x1d, 0x25, 0x2c, 0x37, 0x3e, 0x01, 0x08, 0x13, 0x1a, 0x6d, 0x64, 0x7f, 0x76, 0x49, 0x40, 0x5b, 0x52, 0x3c, 0x35, 0x2e, 0x27, 0x18, 0x11, 0x0a, 0x03, 0x74, 0x7d, 0x66, 0x6f, 0x50, 0x59, 0x42, 0x4b, 0x17, 0x1e, 0x05, 0x0c, 0x33, 0x3a, 0x21, 0x28, 0x5f, 0x56, 0x4d, 0x44, 0x7b, 0x72, 0x69, 0x60, 0x0e, 0x07, 0x1c, 0x15, 0x2a, 0x23, 0x38, 0x31, 0x46, 0x4f, 0x54, 0x5d, 0x62, 0x6b, 0x70, 0x79 }; /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ static bool mmc_read(void *instance, uint32_t startblk, uint8_t *buffer, uint32_t n) { if (mmcStartSequentialRead((MMCDriver *)instance, startblk)) { return HAL_FAILED; } while (n > 0U) { if (mmcSequentialRead((MMCDriver *)instance, buffer)) { return HAL_FAILED; } buffer += MMCSD_BLOCK_SIZE; n--; } if (mmcStopSequentialRead((MMCDriver *)instance)) { return HAL_FAILED; } return HAL_SUCCESS; } static bool mmc_write(void *instance, uint32_t startblk, const uint8_t *buffer, uint32_t n) { if (mmcStartSequentialWrite((MMCDriver *)instance, startblk)) { return HAL_FAILED; } while (n > 0U) { if (mmcSequentialWrite((MMCDriver *)instance, buffer)) { return HAL_FAILED; } buffer += MMCSD_BLOCK_SIZE; n--; } if (mmcStopSequentialWrite((MMCDriver *)instance)) { return HAL_FAILED; } return HAL_SUCCESS; } /** * @brief Calculate the MMC standard CRC-7 based on a lookup table. * * @param[in] crc start value for CRC * @param[in] buffer pointer to data buffer * @param[in] len length of data * @return Calculated CRC */ static uint8_t crc7(uint8_t crc, const uint8_t *buffer, size_t len) { while (len > 0U) { crc = crc7_lookup_table[(crc << 1) ^ (*buffer++)]; len--; } return crc; } /** * @brief Waits an idle condition. * * @param[in] mmcp pointer to the @p MMCDriver object * * @notapi */ static void wait(MMCDriver *mmcp) { int i; uint8_t buf[4]; for (i = 0; i < 16; i++) { spiReceive(mmcp->config->spip, 1, buf); if (buf[0] == 0xFFU) { return; } } /* Looks like it is a long wait.*/ while (true) { spiReceive(mmcp->config->spip, 1, buf); if (buf[0] == 0xFFU) { break; } #if MMC_NICE_WAITING == TRUE /* Trying to be nice with the other threads.*/ osalThreadSleepMilliseconds(1); #endif } } /** * @brief Sends a command header. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[in] cmd the command id * @param[in] arg the command argument * * @notapi */ static void send_hdr(MMCDriver *mmcp, uint8_t cmd, uint32_t arg) { uint8_t buf[6]; /* Wait for the bus to become idle if a write operation was in pr
/*
             LUFA Library
     Copyright (C) Dean Camera, 2017.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Header file for AudioOutput.c.
 */

#ifndef _AUDIO_OUTPUT_H_
#define _AUDIO_OUTPUT_H_

	/* Includes: */
		#include <avr/io.h>
		#include <avr/wdt.h>
		#include <avr/power.h>
		#include <avr/interrupt.h>
		#include <stdlib.h>

		#include "Descriptors.h"
		#include "Config/AppConfig.h"

		#include <LUFA/Drivers/Board/LEDs.h>
		#include <LUFA/Drivers/USB/USB.h>
		#include <LUFA/Platform/Platform.h>

	/* Macros: */
		/** LED mask for the library LED driver, to indicate that the USB interface is not ready. */
		#define LEDMASK_USB_NOTREADY      LEDS_LED1

		/** LED mask for the library LED driver, to indicate that the USB interface is enumerating. */
		#define LEDMASK_USB_ENUMERATING  (LEDS_LED2 | LEDS_LED3)

		/** LED mask for the library LED driver, to indicate that the USB interface is ready. */
		#define LEDMASK_USB_READY        (LEDS_LED2 | LEDS_LED4)

		/** LED mask for the library LED driver, to indicate that an error has occurred in the USB interface. */
		#define LEDMASK_USB_ERROR        (LEDS_LED1 | LEDS_LED3)

	/* Function Prototypes: */
		void SetupHardware(void);

		void EVENT_USB_Device_Connect(void);
		void EVENT_USB_Device_Disconnect(void);
		void EVENT_USB_Device_ConfigurationChanged(void);
		void EVENT_USB_Device_ControlRequest(void);

		bool CALLBACK_Audio_Device_GetSetEndpointProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
		                                                  const uint8_t EndpointProperty,
		                                                  const uint8_t EndpointAddress,
		                                                  const uint8_t EndpointControl,
		                                                  uint16_t* const DataLength,
		                                                  uint8_t* Data) ATTR_NON_NULL_PTR_ARG(1);
		bool CALLBACK_Audio_Device_GetSetInterfaceProperty(USB_ClassInfo_Audio_Device_t* const AudioInterfaceInfo,
		                                                   const uint8_t Property,
		                                                   const uint8_t EntityAddress,
		                                                   const uint16_t Parameter,
		                                                   uint16_t* const DataLength,
		                                                   uint8_t* Data);
#endif
AILED the operation failed. * * @api */ bool mmcStopSequentialRead(MMCDriver *mmcp) { static const uint8_t stopcmd[] = { (uint8_t)(0x40U | MMCSD_CMD_STOP_TRANSMISSION), 0, 0, 0, 0, 1, 0xFF }; osalDbgCheck(mmcp != NULL); if (mmcp->state != BLK_READING) { return HAL_FAILED; } spiSend(mmcp->config->spip, sizeof(stopcmd), stopcmd); /* result = recvr1(mmcp) != 0x00U;*/ /* Note, ignored r1 response, it can be not zero, unknown issue.*/ (void) recvr1(mmcp); /* Read operation finished.*/ spiUnselect(mmcp->config->spip); mmcp->state = BLK_READY; return HAL_SUCCESS; } /** * @brief Starts a sequential write. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[in] startblk first block to write * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcStartSequentialWrite(MMCDriver *mmcp, uint32_t startblk) { osalDbgCheck(mmcp != NULL); osalDbgAssert(mmcp->state == BLK_READY, "invalid state"); /* Write operation in progress.*/ mmcp->state = BLK_WRITING; spiStart(mmcp->config->spip, mmcp->config->hscfg); spiSelect(mmcp->config->spip); if (mmcp->block_addresses) { send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk); } else { send_hdr(mmcp, MMCSD_CMD_WRITE_MULTIPLE_BLOCK, startblk * MMCSD_BLOCK_SIZE); } if (recvr1(mmcp) != 0x00U) { spiStop(mmcp->config->spip); mmcp->state = BLK_READY; return HAL_FAILED; } return HAL_SUCCESS; } /** * @brief Writes a block within a sequential write operation. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[out] buffer pointer to the write buffer * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcSequentialWrite(MMCDriver *mmcp, const uint8_t *buffer) { static const uint8_t start[] = {0xFF, 0xFC}; uint8_t b[1]; osalDbgCheck((mmcp != NULL) && (buffer != NULL)); if (mmcp->state != BLK_WRITING) { return HAL_FAILED; } spiSend(mmcp->config->spip, sizeof(start), start); /* Data prologue. */ spiSend(mmcp->config->spip, MMCSD_BLOCK_SIZE, buffer);/* Data. */ spiIgnore(mmcp->config->spip, 2); /* CRC ignored. */ spiReceive(mmcp->config->spip, 1, b); if ((b[0] & 0x1FU) == 0x05U) { wait(mmcp); return HAL_SUCCESS; } /* Error.*/ spiUnselect(mmcp->config->spip); spiStop(mmcp->config->spip); mmcp->state = BLK_READY; return HAL_FAILED; } /** * @brief Stops a sequential write gracefully. * * @param[in] mmcp pointer to the @p MMCDriver object * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcStopSequentialWrite(MMCDriver *mmcp) { static const uint8_t stop[] = {0xFD, 0xFF}; osalDbgCheck(mmcp != NULL); if (mmcp->state != BLK_WRITING) { return HAL_FAILED; } spiSend(mmcp->config->spip, sizeof(stop), stop); spiUnselect(mmcp->config->spip); /* Write operation finished.*/ mmcp->state = BLK_READY; return HAL_SUCCESS; } /** * @brief Waits for card idle condition. * * @param[in] mmcp pointer to the @p MMCDriver object * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcSync(MMCDriver *mmcp) { osalDbgCheck(mmcp != NULL); if (mmcp->state != BLK_READY) { return HAL_FAILED; } /* Synchronization operation in progress.*/ mmcp->state = BLK_SYNCING; spiStart(mmcp->config->spip, mmcp->config->hscfg); sync(mmcp); /* Synchronization operation finished.*/ mmcp->state = BLK_READY; return HAL_SUCCESS; } /** * @brief Returns the media info. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[out] bdip pointer to a @p BlockDeviceInfo structure * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcGetInfo(MMCDriver *mmcp, BlockDeviceInfo *bdip) { osalDbgCheck((mmcp != NULL) && (bdip != NULL)); if (mmcp->state != BLK_READY) { return HAL_FAILED; } bdip->blk_num = mmcp->capacity; bdip->blk_size = MMCSD_BLOCK_SIZE; return HAL_SUCCESS; } /** * @brief Erases blocks. * * @param[in] mmcp pointer to the @p MMCDriver object * @param[in] startblk starting block number * @param[in] endblk ending block number * * @return The operation status. * @retval HAL_SUCCESS the operation succeeded. * @retval HAL_FAILED the operation failed. * * @api */ bool mmcErase(MMCDriver *mmcp, uint32_t startblk, uint32_t endblk) { osalDbgCheck((mmcp != NULL)); /* Erase operation in progress.*/ mmcp->state = BLK_WRITING; /* Handling command differences between HC and normal cards.*/ if (!mmcp->block_addresses) { startblk *= MMCSD_BLOCK_SIZE; endblk *= MMCSD_BLOCK_SIZE; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_START, startblk) != 0x00U) { goto failed; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE_RW_BLK_END, endblk) != 0x00U) { goto failed; } if (send_command_R1(mmcp, MMCSD_CMD_ERASE, 0) != 0x00U) { goto failed; } mmcp->state = BLK_READY; return HAL_SUCCESS; /* Command failed, state reset to BLK_ACTIVE.*/ failed: spiStop(mmcp->config->spip); mmcp->state = BLK_READY; return HAL_FAILED; } #endif /* HAL_USE_MMC_SPI == TRUE */ /** @} */