| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477 |
- /**
- * @file usbd_audio.c
- * @brief
- *
- * Copyright (c) 2022 sakumisu
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership. The
- * ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the
- * License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations
- * under the License.
- *
- */
- #include "usbd_core.h"
- #include "usbd_audio.h"
- #if CONFIG_USBDEV_AUDIO_VERSION < 0x0200
- struct usbd_audio_volume_info {
- uint16_t vol_min;
- uint16_t vol_max;
- uint16_t vol_res;
- uint16_t vol_current;
- };
- struct usbd_audio_attribute_control {
- struct usbd_audio_volume_info volume[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- uint8_t mute[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- uint8_t automatic_gain[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- };
- #else
- struct audio_v2_control_range2_param_block_default {
- uint16_t wNumSubRanges;
- struct
- {
- uint16_t wMin;
- uint16_t wMax;
- uint16_t wRes;
- } subrange[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- } __PACKED;
- struct usbd_audio_attribute_control {
- uint32_t volume_bCUR;
- uint32_t mute_bCUR;
- struct audio_v2_control_range2_param_block_default volume;
- uint8_t mute[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- uint32_t sampling_freq[CONFIG_USBDEV_AUDIO_MAX_CHANNEL];
- };
- #endif
- struct audio_entity_info {
- usb_slist_t list;
- uint8_t bDescriptorSubtype;
- uint8_t bEntityId;
- void *priv;
- };
- static usb_slist_t usbd_audio_entity_info_head = USB_SLIST_OBJECT_INIT(usbd_audio_entity_info_head);
- const uint8_t default_sampling_freq_table[] = {
- AUDIO_SAMPLE_FREQ_NUM(5),
- AUDIO_SAMPLE_FREQ_4B(8000),
- AUDIO_SAMPLE_FREQ_4B(8000),
- AUDIO_SAMPLE_FREQ_4B(0x00),
- AUDIO_SAMPLE_FREQ_4B(16000),
- AUDIO_SAMPLE_FREQ_4B(16000),
- AUDIO_SAMPLE_FREQ_4B(0x00),
- AUDIO_SAMPLE_FREQ_4B(32000),
- AUDIO_SAMPLE_FREQ_4B(32000),
- AUDIO_SAMPLE_FREQ_4B(0x00),
- AUDIO_SAMPLE_FREQ_4B(44100),
- AUDIO_SAMPLE_FREQ_4B(44100),
- AUDIO_SAMPLE_FREQ_4B(0x00),
- AUDIO_SAMPLE_FREQ_4B(48000),
- AUDIO_SAMPLE_FREQ_4B(48000),
- AUDIO_SAMPLE_FREQ_4B(0x00),
- // AUDIO_SAMPLE_FREQ_4B(88200),
- // AUDIO_SAMPLE_FREQ_4B(88200),
- // AUDIO_SAMPLE_FREQ_4B(0x00),
- // AUDIO_SAMPLE_FREQ_4B(96000),
- // AUDIO_SAMPLE_FREQ_4B(96000),
- // AUDIO_SAMPLE_FREQ_4B(0x00),
- // AUDIO_SAMPLE_FREQ_4B(192000),
- // AUDIO_SAMPLE_FREQ_4B(192000),
- // AUDIO_SAMPLE_FREQ_4B(0x00),
- };
- #if CONFIG_USBDEV_AUDIO_VERSION < 0x0200
- static int audio_custom_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
- {
- uint8_t control_selector;
- uint32_t sampling_freq = 0;
- uint8_t pitch_enable;
- uint8_t ep;
- if ((setup->bmRequestType & USB_REQUEST_RECIPIENT_MASK) == USB_REQUEST_RECIPIENT_ENDPOINT) {
- control_selector = HI_BYTE(setup->wValue);
- ep = LO_BYTE(setup->wIndex);
- switch (setup->bRequest) {
- case AUDIO_REQUEST_SET_CUR:
- switch (control_selector) {
- case AUDIO_EP_CONTROL_SAMPLING_FEQ:
- memcpy((uint8_t *)&sampling_freq, *data, *len);
- USB_LOG_DBG("Set ep:%02x %d Hz\r\n", ep, (int)sampling_freq);
- usbd_audio_set_sampling_freq(0, ep, sampling_freq);
- break;
- case AUDIO_EP_CONTROL_PITCH:
- pitch_enable = (*data)[0];
- usbd_audio_set_pitch(ep, pitch_enable);
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- break;
- case AUDIO_REQUEST_GET_CUR:
- sampling_freq = 16000;
- memcpy(*data, &sampling_freq, 4);
- *len = 4;
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
- } else {
- return -1;
- }
- return 0;
- }
- #endif
- static int audio_class_request_handler(struct usb_setup_packet *setup, uint8_t **data, uint32_t *len)
- {
- USB_LOG_DBG("AUDIO Class request: "
- "bRequest 0x%02x\r\n",
- setup->bRequest);
- struct audio_entity_info *current_entity_info = NULL;
- struct usbd_audio_attribute_control *current_control = NULL;
- usb_slist_t *i;
- uint8_t entity_id;
- uint8_t control_selector;
- uint8_t ch;
- uint8_t mute;
- uint16_t volume;
- const char *mute_string[2] = { "off", "on" };
- entity_id = HI_BYTE(setup->wIndex);
- control_selector = HI_BYTE(setup->wValue);
- ch = LO_BYTE(setup->wValue);
- ARG_UNUSED(mute_string);
- if (ch > (CONFIG_USBDEV_AUDIO_MAX_CHANNEL - 1)) {
- return -2;
- }
- usb_slist_for_each(i, &usbd_audio_entity_info_head)
- {
- struct audio_entity_info *tmp_entity_info = usb_slist_entry(i, struct audio_entity_info, list);
- if (tmp_entity_info->bEntityId == entity_id) {
- current_entity_info = tmp_entity_info;
- break;
- }
- }
- if (current_entity_info == NULL) {
- return -2;
- }
- current_control = (struct usbd_audio_attribute_control *)current_entity_info->priv;
- if (current_entity_info->bDescriptorSubtype == AUDIO_CONTROL_FEATURE_UNIT) {
- #if CONFIG_USBDEV_AUDIO_VERSION < 0x0200
- float volume2db = 0.0;
- switch (control_selector) {
- case AUDIO_FU_CONTROL_MUTE:
- switch (setup->bRequest) {
- case AUDIO_REQUEST_SET_CUR:
- mute = (*data)[0];
- current_control->mute[ch] = mute;
- USB_LOG_DBG("Set UnitId:%d ch[%d] mute %s\r\n", entity_id, ch, mute_string[mute]);
- usbd_audio_set_mute(entity_id, ch, mute);
- break;
- case AUDIO_REQUEST_GET_CUR:
- (*data)[0] = current_control->mute[ch];
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
- break;
- case AUDIO_FU_CONTROL_VOLUME:
- switch (setup->bRequest) {
- case AUDIO_REQUEST_SET_CUR:
- volume = (((uint16_t)(*data)[1] << 8) | ((uint16_t)(*data)[0]));
- current_control->volume[ch].vol_current = volume;
- if (volume < 0x8000) {
- volume2db = 0.00390625 * volume;
- } else if (volume > 0x8000) {
- volume2db = -0.00390625 * (0xffff - volume + 1);
- }
- USB_LOG_DBG("Set UnitId:%d ch[%d] %0.4f dB\r\n", entity_id, ch, volume2db);
- usbd_audio_set_volume(entity_id, ch, volume2db);
- break;
- case AUDIO_REQUEST_GET_CUR:
- memcpy(*data, ¤t_control->volume[ch].vol_current, 2);
- *len = 2;
- break;
- case AUDIO_REQUEST_GET_MIN:
- memcpy(*data, ¤t_control->volume[ch].vol_min, 2);
- *len = 2;
- break;
- case AUDIO_REQUEST_GET_MAX:
- memcpy(*data, ¤t_control->volume[ch].vol_max, 2);
- *len = 2;
- break;
- case AUDIO_REQUEST_GET_RES:
- memcpy(*data, ¤t_control->volume[ch].vol_res, 2);
- *len = 2;
- break;
- case AUDIO_REQUEST_SET_RES:
- memcpy(¤t_control->volume[ch].vol_res, *data, 2);
- *len = 2;
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- #else
- switch (setup->bRequest) {
- case AUDIO_REQUEST_CUR:
- switch (control_selector) {
- case AUDIO_FU_CONTROL_MUTE:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- (*data)[0] = current_control->mute_bCUR;
- *len = 1;
- } else {
- mute = (*data)[0];
- USB_LOG_DBG("Set UnitId:%d ch[%d] mute %s\r\n", entity_id, ch, mute_string[mute]);
- usbd_audio_set_mute(entity_id, ch, mute);
- }
- break;
- case AUDIO_FU_CONTROL_VOLUME:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- (*data)[0] = current_control->volume_bCUR & 0XFF;
- (*data)[1] = (current_control->volume_bCUR >> 8) & 0xff;
- *len = 2;
- } else {
- volume = (((uint16_t)(*data)[1] << 8) | ((uint16_t)(*data)[0]));
- current_control->volume_bCUR = volume;
- USB_LOG_DBG("Set UnitId:%d ch[%d] %d dB\r\n", entity_id, ch, volume);
- usbd_audio_set_volume(entity_id, ch, volume);
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- break;
- case AUDIO_REQUEST_RANGE:
- switch (control_selector) {
- case AUDIO_FU_CONTROL_VOLUME:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- *((uint16_t *)(*data + 0)) = current_control->volume.wNumSubRanges;
- *((uint16_t *)(*data + 2)) = current_control->volume.subrange[ch].wMin;
- *((uint16_t *)(*data + 4)) = current_control->volume.subrange[ch].wMax;
- *((uint16_t *)(*data + 6)) = current_control->volume.subrange[ch].wRes;
- *len = 8;
- } else {
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
- #endif
- }
- #if CONFIG_USBDEV_AUDIO_VERSION >= 0x0200
- else if (current_entity_info->bDescriptorSubtype == AUDIO_CONTROL_CLOCK_SOURCE) {
- switch (setup->bRequest) {
- case AUDIO_REQUEST_CUR:
- switch (control_selector) {
- case AUDIO_CS_CONTROL_SAM_FREQ:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- uint32_t current_sampling_freq = current_control->sampling_freq[ch];
- memcpy(*data, ¤t_sampling_freq, sizeof(uint32_t));
- *len = 4;
- } else {
- uint32_t sampling_freq;
- memcpy(&sampling_freq, *data, setup->wLength);
- current_control->sampling_freq[ch] = sampling_freq;
- USB_LOG_DBG("Set ClockId:%d ch[%d] %d Hz\r\n", entity_id, ch, (int)sampling_freq);
- usbd_audio_set_sampling_freq(entity_id, ch, sampling_freq);
- }
- break;
- case AUDIO_CS_CONTROL_CLOCK_VALID:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- (*data)[0] = 1;
- *len = 1;
- } else {
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- break;
- case AUDIO_REQUEST_RANGE:
- switch (control_selector) {
- case AUDIO_CS_CONTROL_SAM_FREQ:
- if (setup->bmRequestType & USB_REQUEST_DIR_MASK) {
- uint8_t *sampling_freq_table = NULL;
- uint16_t num;
- usbd_audio_get_sampling_freq_table(entity_id, &sampling_freq_table);
- num = (uint16_t)((uint16_t)(sampling_freq_table[1] << 8) | ((uint16_t)sampling_freq_table[0]));
- *data = sampling_freq_table;
- *len = (12 * num + 2);
- } else {
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class control selector 0x%02x\r\n", control_selector);
- return -1;
- }
- break;
- default:
- USB_LOG_WRN("Unhandled Audio Class bRequest 0x%02x\r\n", setup->bRequest);
- return -1;
- }
- }
- #endif
- else {
- return -1;
- }
- return 0;
- }
- static void audio_notify_handler(uint8_t event, void *arg)
- {
- switch (event) {
- case USBD_EVENT_RESET:
- break;
- case USBD_EVENT_SOF:
- usbd_audio_sof_callback();
- break;
- case USBD_EVENT_SET_INTERFACE: {
- struct usb_interface_descriptor *intf = (struct usb_interface_descriptor *)arg;
- if (intf->bAlternateSetting == 1) {
- usbd_audio_open(intf->bInterfaceNumber);
- } else {
- usbd_audio_close(intf->bInterfaceNumber);
- }
- }
- break;
- default:
- break;
- }
- }
- void usbd_audio_add_interface(usbd_class_t *devclass, usbd_interface_t *intf)
- {
- static usbd_class_t *last_class = NULL;
- if (last_class != devclass) {
- last_class = devclass;
- usbd_class_register(devclass);
- }
- intf->class_handler = audio_class_request_handler;
- #if CONFIG_USBDEV_AUDIO_VERSION < 0x0200
- intf->custom_handler = audio_custom_request_handler;
- #else
- intf->custom_handler = NULL;
- #endif
- intf->vendor_handler = NULL;
- intf->notify_handler = audio_notify_handler;
- usbd_class_add_interface(devclass, intf);
- }
- void usbd_audio_add_entity(uint8_t entity_id, uint16_t bDescriptorSubtype)
- {
- struct audio_entity_info *entity_info = usb_malloc(sizeof(struct audio_entity_info));
- memset(entity_info, 0, sizeof(struct audio_entity_info));
- entity_info->bEntityId = entity_id;
- entity_info->bDescriptorSubtype = bDescriptorSubtype;
- if (bDescriptorSubtype == AUDIO_CONTROL_FEATURE_UNIT) {
- #if CONFIG_USBDEV_AUDIO_VERSION < 0x0200
- struct usbd_audio_attribute_control *control = usb_malloc(sizeof(struct usbd_audio_attribute_control));
- memset(control, 0, sizeof(struct usbd_audio_attribute_control));
- for (uint8_t ch = 0; ch < CONFIG_USBDEV_AUDIO_MAX_CHANNEL; ch++) {
- control->volume[ch].vol_min = 0xdb00;
- control->volume[ch].vol_max = 0x0000;
- control->volume[ch].vol_res = 0x0100;
- control->volume[ch].vol_current = 0xf600;
- control->mute[ch] = 0;
- control->automatic_gain[ch] = 0;
- }
- #else
- struct usbd_audio_attribute_control *control = usb_malloc(sizeof(struct usbd_audio_attribute_control));
- memset(control, 0, sizeof(struct usbd_audio_attribute_control));
- for (uint8_t ch = 0; ch < CONFIG_USBDEV_AUDIO_MAX_CHANNEL; ch++) {
- control->volume.wNumSubRanges = 1;
- control->volume.subrange[ch].wMin = 0;
- control->volume.subrange[ch].wMax = 100;
- control->volume.subrange[ch].wRes = 1;
- control->mute[ch] = 0;
- control->sampling_freq[ch] = 16000;
- control->volume_bCUR = 50;
- control->mute_bCUR = 0;
- }
- #endif
- entity_info->priv = control;
- } else if (bDescriptorSubtype == AUDIO_CONTROL_CLOCK_SOURCE) {
- }
- usb_slist_add_tail(&usbd_audio_entity_info_head, &entity_info->list);
- }
- __WEAK void usbd_audio_set_volume(uint8_t entity_id, uint8_t ch, float dB)
- {
- }
- __WEAK void usbd_audio_set_mute(uint8_t entity_id, uint8_t ch, uint8_t enable)
- {
- }
- __WEAK void usbd_audio_set_sampling_freq(uint8_t entity_id, uint8_t ep_ch, uint32_t sampling_freq)
- {
- }
- __WEAK void usbd_audio_get_sampling_freq_table(uint8_t entity_id, uint8_t **sampling_freq_table)
- {
- *sampling_freq_table = (uint8_t *)default_sampling_freq_table;
- }
- __WEAK void usbd_audio_set_pitch(uint8_t ep, bool enable)
- {
- }
- __WEAK void usbd_audio_sof_callback(void)
- {
- }
|