/****************************************************************************** | |
* @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 | |
} | |