2 ******************************************************************************
3 * @file usbd_audio_core.c
4 * @author MCD Application Team
7 * @brief This file provides the high layer firmware functions to manage the
8 * following functionalities of the USB Audio Class:
9 * - Initialization and Configuration of high and low layer
10 * - Enumeration as Audio Streaming Device
11 * - Audio Streaming data transfer
12 * - AudioControl requests management
17 * ===================================================================
18 * Audio Class Driver Description
19 * ===================================================================
20 * This driver manages the Audio Class 1.0 following the "USB Device Class Definition for
21 * Audio Devices V1.0 Mar 18, 98".
22 * This driver implements the following aspects of the specification:
23 * - Device descriptor management
24 * - Configuration descriptor management
25 * - Standard AC Interface Descriptor management
26 * - 1 Audio Streaming Interface (with single channel, PCM, Stereo mode)
27 * - 1 Audio Streaming Endpoint
28 * - 1 Audio Terminal Input (1 channel)
29 * - Audio Class-Specific AC Interfaces
30 * - Audio Class-Specific AS Interfaces
31 * - AudioControl Requests: only SET_CUR and GET_CUR requests are supported (for Mute)
32 * - Audio Feature Unit (limited to Mute control)
33 * - Audio Synchronization type: Asynchronous
34 * - Single fixed audio sampling rate (configurable in usbd_conf.h file)
37 * The Audio Class 1.0 is based on USB Specification 1.0 and thus supports only
38 * Low and Full speed modes and does not allow High Speed transfers.
39 * Please refer to "USB Device Class Definition for Audio Devices V1.0 Mar 18, 98"
42 * These aspects may be enriched or modified for a specific user application.
44 * This driver doesn't implement the following aspects of the specification
45 * (but it is possible to manage these features with some modifications on this driver):
46 * - AudioControl Endpoint management
47 * - AudioControl requsests other than SET_CUR and GET_CUR
48 * - Abstraction layer for AudioControl requests (only Mute functionality is managed)
49 * - Audio Synchronization type: Adaptive
50 * - Audio Compression modules and interfaces
51 * - MIDI interfaces and modules
52 * - Mixer/Selector/Processing/Extension Units (Feature unit is limited to Mute control)
53 * - Any other application-specific modules
54 * - Multiple and Variable audio sampling rates
55 * - Out Streaming Endpoint/Interface (microphone)
59 ******************************************************************************
62 * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
63 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
64 * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
65 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
66 * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
67 * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
69 * <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
70 ******************************************************************************
73 /* Includes ------------------------------------------------------------------*/
75 #include "usbd_audio_core.h"
76 #include "usbd_audio_out_if.h"
78 /** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY
83 /** @defgroup usbd_audio
84 * @brief usbd core module
88 /** @defgroup usbd_audio_Private_TypesDefinitions
96 /** @defgroup usbd_audio_Private_Defines
104 /** @defgroup usbd_audio_Private_Macros
112 /** @defgroup usbd_audio_Private_FunctionPrototypes
116 /*********************************************
117 AUDIO Device library callbacks
118 *********************************************/
119 static uint8_t usbd_audio_Init (void *pdev, uint8_t cfgidx);
120 static uint8_t usbd_audio_DeInit (void *pdev, uint8_t cfgidx);
121 static uint8_t usbd_audio_Setup (void *pdev, USB_SETUP_REQ *req);
122 static uint8_t usbd_audio_EP0_RxReady(void *pdev);
123 static uint8_t usbd_audio_DataIn (void *pdev, uint8_t epnum);
124 static uint8_t usbd_audio_DataOut (void *pdev, uint8_t epnum);
125 static uint8_t usbd_audio_SOF (void *pdev);
126 static uint8_t usbd_audio_OUT_Incplt (void *pdev);
128 /*********************************************
129 AUDIO Requests management functions
130 *********************************************/
131 static void AUDIO_Req_GetCurrent(void *pdev, USB_SETUP_REQ *req);
132 static void AUDIO_Req_SetCurrent(void *pdev, USB_SETUP_REQ *req);
133 static uint8_t *USBD_audio_GetCfgDesc (uint8_t speed, uint16_t *length);
138 /** @defgroup usbd_audio_Private_Variables
141 /* Main Buffer for Audio Data Out transfers and its relative pointers */
142 uint8_t IsocOutBuff [TOTAL_OUT_BUF_SIZE * 2];
143 uint8_t* IsocOutWrPtr = IsocOutBuff;
144 uint8_t* IsocOutRdPtr = IsocOutBuff;
146 /* Main Buffer for Audio Control Rrequests transfers and its relative variables */
147 uint8_t AudioCtl[64];
148 uint8_t AudioCtlCmd = 0;
149 uint32_t AudioCtlLen = 0;
150 uint8_t AudioCtlUnit = 0;
152 static uint32_t PlayFlag = 0;
154 static __IO uint32_t usbd_audio_AltSet = 0;
155 static uint8_t usbd_audio_CfgDesc[AUDIO_CONFIG_DESC_SIZE];
157 /* AUDIO interface class callbacks structure */
158 USBD_Class_cb_TypeDef AUDIO_cb =
163 NULL, /* EP0_TxSent */
164 usbd_audio_EP0_RxReady,
169 usbd_audio_OUT_Incplt,
170 USBD_audio_GetCfgDesc,
171 #ifdef USB_OTG_HS_CORE
172 USBD_audio_GetCfgDesc, /* use same config as per FS */
176 /* USB AUDIO device Configuration Descriptor */
177 static uint8_t usbd_audio_CfgDesc[AUDIO_CONFIG_DESC_SIZE] =
179 /* Configuration 1 */
181 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */
182 LOBYTE(AUDIO_CONFIG_DESC_SIZE), /* wTotalLength 109 bytes*/
183 HIBYTE(AUDIO_CONFIG_DESC_SIZE),
184 0x02, /* bNumInterfaces */
185 0x01, /* bConfigurationValue */
186 0x00, /* iConfiguration */
187 0xC0, /* bmAttributes BUS Powred*/
188 0x32, /* bMaxPower = 100 mA*/
191 /* USB Speaker Standard interface descriptor */
192 AUDIO_INTERFACE_DESC_SIZE, /* bLength */
193 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
194 0x00, /* bInterfaceNumber */
195 0x00, /* bAlternateSetting */
196 0x00, /* bNumEndpoints */
197 USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
198 AUDIO_SUBCLASS_AUDIOCONTROL, /* bInterfaceSubClass */
199 AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
200 0x00, /* iInterface */
203 /* USB Speaker Class-specific AC Interface Descriptor */
204 AUDIO_INTERFACE_DESC_SIZE, /* bLength */
205 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
206 AUDIO_CONTROL_HEADER, /* bDescriptorSubtype */
207 0x00, /* 1.00 */ /* bcdADC */
209 0x27, /* wTotalLength = 39*/
211 0x01, /* bInCollection */
212 0x01, /* baInterfaceNr */
215 /* USB Speaker Input Terminal Descriptor */
216 AUDIO_INPUT_TERMINAL_DESC_SIZE, /* bLength */
217 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
218 AUDIO_CONTROL_INPUT_TERMINAL, /* bDescriptorSubtype */
219 0x01, /* bTerminalID */
220 0x01, /* wTerminalType AUDIO_TERMINAL_USB_STREAMING 0x0101 */
222 0x00, /* bAssocTerminal */
223 0x01, /* bNrChannels */
224 0x00, /* wChannelConfig 0x0000 Mono */
226 0x00, /* iChannelNames */
227 0x00, /* iTerminal */
230 /* USB Speaker Audio Feature Unit Descriptor */
232 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
233 AUDIO_CONTROL_FEATURE_UNIT, /* bDescriptorSubtype */
234 AUDIO_OUT_STREAMING_CTRL, /* bUnitID */
235 0x01, /* bSourceID */
236 0x01, /* bControlSize */
237 AUDIO_CONTROL_MUTE, /* bmaControls(0) */
238 0x00, /* bmaControls(1) */
239 0x00, /* iTerminal */
242 /*USB Speaker Output Terminal Descriptor */
244 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
245 AUDIO_CONTROL_OUTPUT_TERMINAL, /* bDescriptorSubtype */
246 0x03, /* bTerminalID */
247 0x01, /* wTerminalType 0x0301*/
249 0x00, /* bAssocTerminal */
250 0x02, /* bSourceID */
251 0x00, /* iTerminal */
254 /* USB Speaker Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */
255 /* Interface 1, Alternate Setting 0 */
256 AUDIO_INTERFACE_DESC_SIZE, /* bLength */
257 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
258 0x01, /* bInterfaceNumber */
259 0x00, /* bAlternateSetting */
260 0x00, /* bNumEndpoints */
261 USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
262 AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
263 AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
264 0x00, /* iInterface */
267 /* USB Speaker Standard AS Interface Descriptor - Audio Streaming Operational */
268 /* Interface 1, Alternate Setting 1 */
269 AUDIO_INTERFACE_DESC_SIZE, /* bLength */
270 USB_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
271 0x01, /* bInterfaceNumber */
272 0x01, /* bAlternateSetting */
273 0x01, /* bNumEndpoints */
274 USB_DEVICE_CLASS_AUDIO, /* bInterfaceClass */
275 AUDIO_SUBCLASS_AUDIOSTREAMING, /* bInterfaceSubClass */
276 AUDIO_PROTOCOL_UNDEFINED, /* bInterfaceProtocol */
277 0x00, /* iInterface */
280 /* USB Speaker Audio Streaming Interface Descriptor */
281 AUDIO_STREAMING_INTERFACE_DESC_SIZE, /* bLength */
282 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
283 AUDIO_STREAMING_GENERAL, /* bDescriptorSubtype */
284 0x01, /* bTerminalLink */
286 0x01, /* wFormatTag AUDIO_FORMAT_PCM 0x0001*/
290 /* USB Speaker Audio Type III Format Interface Descriptor */
292 AUDIO_INTERFACE_DESCRIPTOR_TYPE, /* bDescriptorType */
293 AUDIO_STREAMING_FORMAT_TYPE, /* bDescriptorSubtype */
294 AUDIO_FORMAT_TYPE_III, /* bFormatType */
295 0x02, /* bNrChannels */
296 0x02, /* bSubFrameSize : 2 Bytes per frame (16bits) */
297 16, /* bBitResolution (16-bits per sample) */
298 0x01, /* bSamFreqType only one frequency supported */
299 SAMPLE_FREQ(USBD_AUDIO_FREQ), /* Audio sampling frequency coded on 3 bytes */
302 /* Endpoint 1 - Standard Descriptor */
303 AUDIO_STANDARD_ENDPOINT_DESC_SIZE, /* bLength */
304 USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
305 AUDIO_OUT_EP, /* bEndpointAddress 1 out endpoint*/
306 USB_ENDPOINT_TYPE_ISOCHRONOUS, /* bmAttributes */
307 AUDIO_PACKET_SZE(USBD_AUDIO_FREQ), /* wMaxPacketSize in Bytes (Freq(Samples)*2(Stereo)*2(HalfWord)) */
308 0x01, /* bInterval */
310 0x00, /* bSynchAddress */
313 /* Endpoint - Audio Streaming Descriptor*/
314 AUDIO_STREAMING_ENDPOINT_DESC_SIZE, /* bLength */
315 AUDIO_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType */
316 AUDIO_ENDPOINT_GENERAL, /* bDescriptor */
317 0x00, /* bmAttributes */
318 0x00, /* bLockDelayUnits */
319 0x00, /* wLockDelay */
328 /** @defgroup usbd_audio_Private_Functions
333 * @brief usbd_audio_Init
334 * Initilaizes the AUDIO interface.
335 * @param pdev: device instance
336 * @param cfgidx: Configuration index
339 static uint8_t usbd_audio_Init (void *pdev,
348 /* Initialize the Audio output Hardware layer */
349 if (AUDIO_OUT_fops.Init(USBD_AUDIO_FREQ, DEFAULT_VOLUME, 0) != USBD_OK)
354 /* Prepare Out endpoint to receive audio data */
355 DCD_EP_PrepareRx(pdev,
357 (uint8_t*)IsocOutBuff,
364 * @brief usbd_audio_Init
365 * DeInitializes the AUDIO layer.
366 * @param pdev: device instance
367 * @param cfgidx: Configuration index
370 static uint8_t usbd_audio_DeInit (void *pdev,
373 DCD_EP_Close (pdev , AUDIO_OUT_EP);
375 /* DeInitialize the Audio output Hardware layer */
376 if (AUDIO_OUT_fops.DeInit(0) != USBD_OK)
385 * @brief usbd_audio_Setup
386 * Handles the Audio control request parsing.
387 * @param pdev: instance
388 * @param req: usb requests
391 static uint8_t usbd_audio_Setup (void *pdev,
397 switch (req->bmRequest & USB_REQ_TYPE_MASK)
399 /* AUDIO Class Requests -------------------------------*/
400 case USB_REQ_TYPE_CLASS :
401 switch (req->bRequest)
403 case AUDIO_REQ_GET_CUR:
404 AUDIO_Req_GetCurrent(pdev, req);
407 case AUDIO_REQ_SET_CUR:
408 AUDIO_Req_SetCurrent(pdev, req);
412 USBD_CtlError (pdev, req);
417 /* Standard Requests -------------------------------*/
418 case USB_REQ_TYPE_STANDARD:
419 switch (req->bRequest)
421 case USB_REQ_GET_DESCRIPTOR:
422 if( (req->wValue >> 8) == AUDIO_DESCRIPTOR_TYPE)
424 #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED
425 pbuf = usbd_audio_Desc;
427 pbuf = usbd_audio_CfgDesc + 18;
429 len = MIN(USB_AUDIO_DESC_SIZ , req->wLength);
432 USBD_CtlSendData (pdev,
437 case USB_REQ_GET_INTERFACE :
438 USBD_CtlSendData (pdev,
439 (uint8_t *)&usbd_audio_AltSet,
443 case USB_REQ_SET_INTERFACE :
444 if ((uint8_t)(req->wValue) < AUDIO_TOTAL_IF_NUM)
446 usbd_audio_AltSet = (uint8_t)(req->wValue);
450 /* Call the error management function (command will be nacked */
451 USBD_CtlError (pdev, req);
460 * @brief usbd_audio_EP0_RxReady
461 * Handles audio control requests data.
462 * @param pdev: device device instance
465 static uint8_t usbd_audio_EP0_RxReady (void *pdev)
467 /* Check if an AudioControl request has been issued */
468 if (AudioCtlCmd == AUDIO_REQ_SET_CUR)
469 {/* In this driver, to simplify code, only SET_CUR request is managed */
470 /* Check for which addressed unit the AudioControl request has been issued */
471 if (AudioCtlUnit == AUDIO_OUT_STREAMING_CTRL)
472 {/* In this driver, to simplify code, only one unit is manage */
473 /* Call the audio interface mute function */
474 AUDIO_OUT_fops.MuteCtl(AudioCtl[0]);
476 /* Reset the AudioCtlCmd variable to prevent re-entering this function */
486 * @brief usbd_audio_DataIn
487 * Handles the audio IN data stage.
488 * @param pdev: instance
489 * @param epnum: endpoint number
492 static uint8_t usbd_audio_DataIn (void *pdev, uint8_t epnum)
498 * @brief usbd_audio_DataOut
499 * Handles the Audio Out data stage.
500 * @param pdev: instance
501 * @param epnum: endpoint number
504 static uint8_t usbd_audio_DataOut (void *pdev, uint8_t epnum)
506 if (epnum == AUDIO_OUT_EP)
508 /* Increment the Buffer pointer or roll it back when all buffers are full */
509 if (IsocOutWrPtr >= (IsocOutBuff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM)))
510 {/* All buffers are full: roll back */
511 IsocOutWrPtr = IsocOutBuff;
514 {/* Increment the buffer pointer */
515 IsocOutWrPtr += AUDIO_OUT_PACKET;
518 /* Toggle the frame index */
519 ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].even_odd_frame =
520 (((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].even_odd_frame)? 0:1;
522 /* Prepare Out endpoint to receive next audio packet */
523 DCD_EP_PrepareRx(pdev,
525 (uint8_t*)(IsocOutWrPtr),
528 /* Trigger the start of streaming only when half buffer is full */
529 if ((PlayFlag == 0) && (IsocOutWrPtr >= (IsocOutBuff + ((AUDIO_OUT_PACKET * OUT_PACKET_NUM) / 2))))
531 /* Enable start of Streaming */
540 * @brief usbd_audio_SOF
541 * Handles the SOF event (data buffer update and synchronization).
542 * @param pdev: instance
543 * @param epnum: endpoint number
546 static uint8_t usbd_audio_SOF (void *pdev)
548 /* Check if there are available data in stream buffer.
549 In this function, a single variable (PlayFlag) is used to avoid software delays.
550 The play operation must be executed as soon as possible after the SOF detection. */
553 /* Start playing received packet */
554 AUDIO_OUT_fops.AudioCmd((uint8_t*)(IsocOutRdPtr), /* Samples buffer pointer */
555 AUDIO_OUT_PACKET, /* Number of samples in Bytes */
556 AUDIO_CMD_PLAY); /* Command to be processed */
558 /* Increment the Buffer pointer or roll it back when all buffers all full */
559 if (IsocOutRdPtr >= (IsocOutBuff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM)))
560 {/* Roll back to the start of buffer */
561 IsocOutRdPtr = IsocOutBuff;
564 {/* Increment to the next sub-buffer */
565 IsocOutRdPtr += AUDIO_OUT_PACKET;
568 /* If all available buffers have been consumed, stop playing */
569 if (IsocOutRdPtr == IsocOutWrPtr)
571 /* Pause the audio stream */
572 AUDIO_OUT_fops.AudioCmd((uint8_t*)(IsocOutBuff), /* Samples buffer pointer */
573 AUDIO_OUT_PACKET, /* Number of samples in Bytes */
574 AUDIO_CMD_PAUSE); /* Command to be processed */
576 /* Stop entering play loop */
579 /* Reset buffer pointers */
580 IsocOutRdPtr = IsocOutBuff;
581 IsocOutWrPtr = IsocOutBuff;
589 * @brief usbd_audio_OUT_Incplt
590 * Handles the iso out incomplete event.
591 * @param pdev: instance
594 static uint8_t usbd_audio_OUT_Incplt (void *pdev)
599 /******************************************************************************
600 AUDIO Class requests management
601 ******************************************************************************/
603 * @brief AUDIO_Req_GetCurrent
604 * Handles the GET_CUR Audio control request.
605 * @param pdev: instance
606 * @param req: setup class request
609 static void AUDIO_Req_GetCurrent(void *pdev, USB_SETUP_REQ *req)
611 /* Send the current mute state */
612 USBD_CtlSendData (pdev,
618 * @brief AUDIO_Req_SetCurrent
619 * Handles the SET_CUR Audio control request.
620 * @param pdev: instance
621 * @param req: setup class request
624 static void AUDIO_Req_SetCurrent(void *pdev, USB_SETUP_REQ *req)
628 /* Prepare the reception of the buffer over EP0 */
629 USBD_CtlPrepareRx (pdev,
633 /* Set the global variables indicating current request and its length
634 to the function usbd_audio_EP0_RxReady() which will process the request */
635 AudioCtlCmd = AUDIO_REQ_SET_CUR; /* Set the request value */
636 AudioCtlLen = req->wLength; /* Set the request data length */
637 AudioCtlUnit = HIBYTE(req->wIndex); /* Set the request target unit */
642 * @brief USBD_audio_GetCfgDesc
643 * Returns configuration descriptor.
644 * @param speed : current device speed
645 * @param length : pointer data length
646 * @retval pointer to descriptor buffer
648 static uint8_t *USBD_audio_GetCfgDesc (uint8_t speed, uint16_t *length)
650 *length = sizeof (usbd_audio_CfgDesc);
651 return usbd_audio_CfgDesc;
665 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/