| /****************************************************************************** |
| * @file usbaud.c |
| * |
| * @brief for TLSR chips |
| * |
| * @author public@telink-semi.com; |
| * @date Sep. 30, 2010 |
| * |
| * @attention |
| * |
| * Copyright (C) 2019-2020 Telink Semiconductor (Shanghai) Co., Ltd. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *****************************************************************************/ |
| #include "../../common/config/user_config.h" |
| |
| #include "drivers.h" |
| |
| #include "usbaud.h" |
| #include "../usbstd/usbhw.h" |
| #include "../usbstd/usbhw_i.h" |
| #include "../usbstd/usb.h" |
| #include "../usbstd/AudioClassCommon.h" |
| |
| /************************************************* |
| * g_audio_hid_chg: |
| * 0x00: no event |
| * 0x01: speaker volume change |
| * 0x02: speaker mute change |
| * 0x11: microphone volume change |
| * 0x12: microphone mute change |
| *************************************************/ |
| |
| static speaker_setting_t speaker_setting; |
| static mic_setting_t mic_setting; |
| void usbaud_set_audio_mode(int iso_en, int mono_en) { |
| assert(USB_EDP_MIC < 8); |
| SET_FLD(reg_usb_ep_ctrl(USB_EDP_MIC), FLD_USB_EP_EOF_ISO | FLD_USB_EP_MONO); |
| } |
| |
| #if 0 |
| void usbaud_hid_report(char format, char volume) { |
| unsigned char sAudioHidReport[] = { 0x01,/* report ID */ |
| format,/*[0]:play/pause, |
| [1]:scan next track, |
| [2]:scan previous track, |
| [3]:stop, |
| [4]:play, |
| [5]:pause, |
| [6]:fast forward, |
| [7]:rewind, |
| */ |
| volume /*[0]:volume up |
| [1]:volume down |
| [2]:mute |
| [3:7] 0; |
| */ |
| }; |
| WriteEndPoint(EDP_ID_AUDIO_HID, sAudioHidReport, sizeof(sAudioHidReport)); |
| } |
| #endif |
| |
| |
| #if(USB_SPEAKER_ENABLE || USB_MIC_ENABLE) // use for volume control, mute, next, prev track, move to mouse hid |
| int usbaud_hid_report(u8 cmd, u8 vol){ |
| if (usbhw_is_ep_busy(USB_EDP_AUDIO_IN)) |
| return 0; |
| reg_usb_ep_ptr(USB_EDP_AUDIO_IN) = 0; |
| |
| // please refer to keyboard_report_desc |
| reg_usb_ep_dat(USB_EDP_AUDIO_IN) = USB_HID_AUDIO; |
| reg_usb_ep_dat(USB_EDP_AUDIO_IN) = cmd; |
| reg_usb_ep_dat(USB_EDP_AUDIO_IN) = vol; |
| |
| reg_usb_ep_ctrl(USB_EDP_AUDIO_IN) = FLD_EP_DAT_ACK; // ACK |
| return 1; |
| } |
| #endif |
| |
| #if 0 |
| u8 usbaud_handle_report(u8 c) { |
| if (USB_REPORT_NO_EVENT == c) { |
| return USB_REPORT_NO_EVENT; |
| } |
| assert(USB_EDP_AUDIO < 8); |
| if(reg_usb_ep_ctrl(USB_EDP_AUDIO) & FLD_USB_EP_BUSY) |
| return c; |
| |
| if(USB_REPORT_RELEASE == c){ |
| usbaud_hid_report(0, 0); |
| return USB_REPORT_NO_EVENT; |
| }else{ |
| usbaud_hid_report((c < 0x10) ? (1 << c) : 0 |
| ,(c < 0x10) ? 0 : (1 << (c & 0x0f))); |
| return USB_REPORT_RELEASE; |
| } |
| } |
| #endif |
| |
| static u16 usbaud_cal_speaker_step(s16 vol){ |
| if(vol < SPEAKER_VOL_MIN) |
| return 0; |
| return (vol - SPEAKER_VOL_MIN) / SPEAKER_VOL_RES; |
| } |
| |
| static u16 usbaud_cal_mic_step(s16 vol){ |
| if(vol < MIC_VOL_MIN) |
| return 0; |
| return (vol - MIC_VOL_MIN) / MIC_VOL_RES; |
| } |
| |
| void usbaud_set_speaker_vol(s16 vol){ |
| speaker_setting.vol_cur = vol; |
| speaker_setting.vol_step = usbaud_cal_speaker_step(vol); |
| } |
| |
| void usbaud_set_mic_vol(s16 vol){ |
| mic_setting.vol_cur = vol; |
| mic_setting.vol_step = usbaud_cal_mic_step(vol); |
| } |
| |
| usb_audio_status_t g_usb_audio_status; |
| |
| u8 usbaud_speaker_vol_get(void){ |
| //return ((g_usb_audio_status.speaker_mute << 7) | g_usb_audio_status.speaker_vol); |
| return (speaker_setting.mute << 7) | (speaker_setting.vol_step & 0x7f); |
| } |
| |
| u8 usbaud_mic_vol_get(void){ |
| //return ((g_usb_audio_status.speaker_mute << 7) | g_usb_audio_status.speaker_vol); |
| return (mic_setting.mute << 7) | (mic_setting.vol_step & 0x7f); |
| } |
| |
| void usbaud_mic_en(int en) { |
| mic_setting.mute = en; |
| } |
| |
| volatile int aaa_audio_intf_set = 0; |
| int usb_audio_class_out_intf_proc(u8 type, u8 feature_id){ |
| int ret = 0; |
| usb_audio_status_t *p_aud = &g_usb_audio_status; |
| |
| aaa_audio_intf_set = 0; |
| aaa_audio_intf_set = (type << 8); |
| aaa_audio_intf_set |= feature_id; |
| switch (type) { |
| // mute control and sample |
| case 0x01: |
| switch (feature_id) { |
| case 0x00://set sample frequency |
| break; |
| case AUDIO_FEATURE_ID_SPEAKER:// Feature ID 0x02, Speaker |
| p_aud->speaker_mute = usbhw_read_ctrl_ep_data(); |
| p_aud->change |= 0x1; |
| break; |
| case AUDIO_FEATURE_ID_MIC:// Feature ID 0x05, MIC |
| p_aud->mic_mute = usbhw_read_ctrl_ep_data(); |
| p_aud->change |= 0x2; |
| break; |
| default: |
| ret = 1; |
| break; |
| } |
| break; |
| |
| // volume control |
| case 0x02: |
| switch (feature_id) { |
| case AUDIO_FEATURE_ID_SPEAKER: // Feature ID 0x02, Speaker |
| p_aud->speaker_vol = usbhw_read_ctrl_ep_data() + (usbhw_read_ctrl_ep_data() << 8); |
| p_aud->speaker_vol = ((p_aud->speaker_vol - (short)SPEAKER_VOL_MIN + SPEAKER_VOL_STEP) * (10 - 1)) >> 12; |
| if (p_aud->speaker_vol < 0){ |
| p_aud->speaker_vol = 0; |
| } |
| p_aud->change |= 0x4; |
| break; |
| |
| case AUDIO_FEATURE_ID_MIC: // Feature ID 0x05, MIC |
| p_aud->mic_vol = usbhw_read_ctrl_ep_data() + (usbhw_read_ctrl_ep_data() << 8); |
| p_aud->change |= 0x8; |
| break; |
| |
| default: |
| ret = 1; |
| break; |
| } |
| |
| default: |
| break; |
| } |
| return ret; |
| } |
| |
| // return -1 on fail, 0 on success |
| int usbaud_handle_set_speaker_cmd(int type) { |
| if(type == AUDIO_FEATURE_MUTE){ |
| speaker_setting.mute = usbhw_read_ctrl_ep_data(); |
| }else if(type == AUDIO_FEATURE_VOLUME){ |
| u16 val = usbhw_read_ctrl_ep_u16(); |
| usbaud_set_speaker_vol(val); |
| }else{ |
| return -1; |
| } |
| return 0; |
| } |
| // return -1 on fail, 0 on success |
| int usbaud_handle_set_mic_cmd(int type) { |
| if(type == AUDIO_FEATURE_MUTE){ |
| mic_setting.mute = usbhw_read_ctrl_ep_data(); |
| }else if(type == AUDIO_FEATURE_VOLUME){ |
| u16 val = usbhw_read_ctrl_ep_u16(); |
| usbaud_set_mic_vol(val); |
| }else{ |
| } |
| return 0; |
| } |
| |
| // return -1 on fail, 0 on success |
| int usbaud_handle_get_speaker_cmd(int req, int type) { |
| if(type == AUDIO_FEATURE_MUTE){ |
| usbhw_write_ctrl_ep_data(speaker_setting.mute); |
| }else if(type == AUDIO_FEATURE_VOLUME){ |
| switch (req) { |
| case AUDIO_REQ_GetCurrent: |
| usbhw_write_ctrl_ep_u16(speaker_setting.vol_cur); |
| break; |
| case AUDIO_REQ_GetMinimum: |
| usbhw_write_ctrl_ep_u16(SPEAKER_VOL_MIN); |
| break; |
| case AUDIO_REQ_GetMaximum: |
| usbhw_write_ctrl_ep_u16(SPEAKER_VOL_MAX); |
| break; |
| case AUDIO_REQ_GetResolution: |
| usbhw_write_ctrl_ep_u16(SPEAKER_VOL_RES); |
| break; |
| default: |
| return -1; |
| } |
| }else{ |
| return -1; |
| } |
| return 0; |
| } |
| |
| // return -1 on fail, 0 on success |
| int usbaud_handle_get_mic_cmd(int req, int type) { |
| if(type == AUDIO_FEATURE_MUTE){ |
| usbhw_write_ctrl_ep_data(mic_setting.mute); |
| }else if(type == AUDIO_FEATURE_VOLUME){ |
| switch (req) { |
| case AUDIO_REQ_GetCurrent: |
| usbhw_write_ctrl_ep_u16(mic_setting.vol_cur); |
| break; |
| case AUDIO_REQ_GetMinimum: |
| usbhw_write_ctrl_ep_u16(MIC_VOL_MIN); |
| break; |
| case AUDIO_REQ_GetMaximum: |
| usbhw_write_ctrl_ep_u16(MIC_VOL_MAX); |
| break; |
| case AUDIO_REQ_GetResolution: |
| usbhw_write_ctrl_ep_u16(MIC_VOL_RES); |
| break; |
| default: |
| return -1; |
| } |
| }else{ |
| return -1; |
| } |
| return 0; |
| } |
| void usbaud_init(void) { |
| if (USB_MIC_ENABLE && 1 == MIC_CHANNEL_COUNT) { |
| usbaud_set_audio_mode(1, 1); |
| } |
| #if (USB_SPEAKER_ENABLE) |
| usbaud_set_speaker_vol(SPEAKER_VOL_MAX); |
| #endif |
| #if (USB_MIC_ENABLE) |
| mic_setting.vol_cur = MIC_VOL_DEF; |
| #endif |
| } |
| |