usbh_audio.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /*
  2. * Copyright (c) 2022, sakumisu
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include "usbh_core.h"
  7. #include "usbh_audio.h"
  8. #undef USB_DBG_TAG
  9. #define USB_DBG_TAG "usbh_audio"
  10. #include "usb_log.h"
  11. #define DEV_FORMAT "/dev/audio%d"
  12. /* general descriptor field offsets */
  13. #define DESC_bLength 0 /** Length offset */
  14. #define DESC_bDescriptorType 1 /** Descriptor type offset */
  15. #define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
  16. /* interface descriptor field offsets */
  17. #define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
  18. #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
  19. USB_NOCACHE_RAM_SECTION USB_MEM_ALIGNX uint8_t g_audio_buf[128];
  20. static struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
  21. static uint32_t g_devinuse = 0;
  22. static struct usbh_audio *usbh_audio_class_alloc(void)
  23. {
  24. uint8_t devno;
  25. for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
  26. if ((g_devinuse & (1U << devno)) == 0) {
  27. g_devinuse |= (1U << devno);
  28. memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
  29. g_audio_class[devno].minor = devno;
  30. return &g_audio_class[devno];
  31. }
  32. }
  33. return NULL;
  34. }
  35. static void usbh_audio_class_free(struct usbh_audio *audio_class)
  36. {
  37. uint8_t devno = audio_class->minor;
  38. if (devno < 32) {
  39. g_devinuse &= ~(1U << devno);
  40. }
  41. memset(audio_class, 0, sizeof(struct usbh_audio));
  42. }
  43. int usbh_audio_open(struct usbh_audio *audio_class, const char *name, uint32_t samp_freq, uint8_t bitresolution)
  44. {
  45. struct usb_setup_packet *setup;
  46. struct usb_endpoint_descriptor *ep_desc;
  47. uint8_t mult;
  48. uint16_t mps;
  49. int ret;
  50. uint8_t intf = 0xff;
  51. uint8_t altsetting = 1;
  52. if (!audio_class || !audio_class->hport) {
  53. return -USB_ERR_INVAL;
  54. }
  55. setup = audio_class->hport->setup;
  56. if (audio_class->is_opened) {
  57. return 0;
  58. }
  59. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  60. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  61. intf = audio_class->as_msg_table[i].stream_intf;
  62. for (uint8_t j = 1; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
  63. if (audio_class->as_msg_table[i].as_format[j].bBitResolution == bitresolution) {
  64. for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
  65. uint32_t freq = 0;
  66. memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
  67. if (freq == samp_freq) {
  68. altsetting = j;
  69. goto freq_found;
  70. }
  71. }
  72. }
  73. }
  74. }
  75. }
  76. return -USB_ERR_NODEV;
  77. freq_found:
  78. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
  79. setup->bRequest = USB_REQUEST_SET_INTERFACE;
  80. setup->wValue = altsetting;
  81. setup->wIndex = intf;
  82. setup->wLength = 0;
  83. ret = usbh_control_transfer(audio_class->hport, setup, NULL);
  84. if (ret < 0) {
  85. return ret;
  86. }
  87. ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
  88. if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].ep_attr & AUDIO_EP_CONTROL_SAMPLING_FEQ) {
  89. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_ENDPOINT;
  90. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  91. setup->wValue = (AUDIO_EP_CONTROL_SAMPLING_FEQ << 8) | 0x00;
  92. setup->wIndex = ep_desc->bEndpointAddress;
  93. setup->wLength = 3;
  94. memcpy(g_audio_buf, &samp_freq, 3);
  95. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  96. if (ret < 0) {
  97. return ret;
  98. }
  99. }
  100. mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
  101. mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
  102. if (ep_desc->bEndpointAddress & 0x80) {
  103. audio_class->isoin_mps = mps * (mult + 1);
  104. USBH_EP_INIT(audio_class->isoin, ep_desc);
  105. } else {
  106. audio_class->isoout_mps = mps * (mult + 1);
  107. USBH_EP_INIT(audio_class->isoout, ep_desc);
  108. }
  109. USB_LOG_INFO("Open audio stream :%s, altsetting: %u\r\n", name, altsetting);
  110. audio_class->is_opened = true;
  111. return ret;
  112. }
  113. int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
  114. {
  115. struct usb_setup_packet *setup;
  116. struct usb_endpoint_descriptor *ep_desc;
  117. int ret;
  118. uint8_t intf = 0xff;
  119. uint8_t altsetting = 1;
  120. if (!audio_class || !audio_class->hport) {
  121. return -USB_ERR_INVAL;
  122. }
  123. setup = audio_class->hport->setup;
  124. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  125. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  126. intf = audio_class->as_msg_table[i].stream_intf;
  127. }
  128. }
  129. if (intf == 0xff) {
  130. return -USB_ERR_NODEV;
  131. }
  132. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_STANDARD | USB_REQUEST_RECIPIENT_INTERFACE;
  133. setup->bRequest = USB_REQUEST_SET_INTERFACE;
  134. setup->wValue = 0;
  135. setup->wIndex = intf;
  136. setup->wLength = 0;
  137. ret = usbh_control_transfer(audio_class->hport, setup, NULL);
  138. if (ret < 0) {
  139. return ret;
  140. }
  141. USB_LOG_INFO("Close audio stream :%s\r\n", name);
  142. audio_class->is_opened = false;
  143. ep_desc = &audio_class->hport->config.intf[intf].altsetting[altsetting].ep[0].ep_desc;
  144. if (ep_desc->bEndpointAddress & 0x80) {
  145. if (audio_class->isoin) {
  146. audio_class->isoin = NULL;
  147. }
  148. } else {
  149. if (audio_class->isoout) {
  150. audio_class->isoout = NULL;
  151. }
  152. }
  153. return ret;
  154. }
  155. int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, uint8_t ch, int volume_db)
  156. {
  157. struct usb_setup_packet *setup;
  158. int ret;
  159. uint8_t feature_id = 0xff;
  160. uint8_t intf;
  161. uint16_t volume_hex;
  162. int volume_min_db;
  163. int volume_max_db;
  164. if (!audio_class || !audio_class->hport) {
  165. return -USB_ERR_INVAL;
  166. }
  167. if ((volume_db > 127) || (volume_db < -127)) {
  168. return -USB_ERR_INVAL;
  169. }
  170. setup = audio_class->hport->setup;
  171. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  172. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  173. feature_id = audio_class->as_msg_table[i].feature_terminal_id;
  174. intf = audio_class->as_msg_table[i].stream_intf;
  175. }
  176. }
  177. if (feature_id == 0xff) {
  178. return -USB_ERR_NODEV;
  179. }
  180. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  181. setup->bRequest = AUDIO_REQUEST_GET_CUR;
  182. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  183. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  184. setup->wLength = 2;
  185. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  186. if (ret < 0) {
  187. return ret;
  188. }
  189. memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur, g_audio_buf, 2);
  190. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  191. setup->bRequest = AUDIO_REQUEST_GET_MIN;
  192. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  193. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  194. setup->wLength = 2;
  195. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  196. if (ret < 0) {
  197. return ret;
  198. }
  199. memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min, g_audio_buf, 2);
  200. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  201. setup->bRequest = AUDIO_REQUEST_GET_MAX;
  202. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  203. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  204. setup->wLength = 2;
  205. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  206. if (ret < 0) {
  207. return ret;
  208. }
  209. memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max, g_audio_buf, 2);
  210. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  211. setup->bRequest = AUDIO_REQUEST_GET_RES;
  212. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  213. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  214. setup->wLength = 2;
  215. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  216. if (ret < 0) {
  217. return ret;
  218. }
  219. memcpy(&audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_res, g_audio_buf, 2);
  220. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  221. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  222. setup->wValue = (AUDIO_FU_CONTROL_VOLUME << 8) | ch;
  223. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  224. setup->wLength = 2;
  225. if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min < 0x8000) {
  226. volume_min_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min / 256;
  227. } else {
  228. volume_min_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min - 0x10000) / 256;
  229. }
  230. if (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max < 0x8000) {
  231. volume_max_db = audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max / 256;
  232. } else {
  233. volume_max_db = (audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max - 0x10000) / 256;
  234. }
  235. USB_LOG_INFO("Get ch:%d dB range: %d dB ~ %d dB\r\n", volume_min_db, volume_max_db);
  236. if (volume_db >= 0) {
  237. volume_hex = volume_db * 256;
  238. if (volume_hex > audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_max) {
  239. return -USB_ERR_RANGE;
  240. }
  241. } else {
  242. volume_hex = volume_db * 256 + 0x10000;
  243. if (volume_hex < audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_min) {
  244. return -USB_ERR_RANGE;
  245. }
  246. }
  247. memcpy(g_audio_buf, &volume_hex, 2);
  248. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  249. if (ret < 0) {
  250. return ret;
  251. }
  252. audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].volume_cur = volume_hex;
  253. return ret;
  254. }
  255. int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, uint8_t ch, bool mute)
  256. {
  257. struct usb_setup_packet *setup;
  258. int ret;
  259. uint8_t feature_id = 0xff;
  260. uint8_t intf = 0xff;
  261. if (!audio_class || !audio_class->hport) {
  262. return -USB_ERR_INVAL;
  263. }
  264. setup = audio_class->hport->setup;
  265. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  266. if (strcmp(name, audio_class->as_msg_table[i].stream_name) == 0) {
  267. feature_id = audio_class->as_msg_table[i].feature_terminal_id;
  268. intf = audio_class->as_msg_table[i].stream_intf;
  269. }
  270. }
  271. if (feature_id == 0xff) {
  272. return -USB_ERR_NODEV;
  273. }
  274. setup->bmRequestType = USB_REQUEST_DIR_OUT | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  275. setup->bRequest = AUDIO_REQUEST_SET_CUR;
  276. setup->wValue = (AUDIO_FU_CONTROL_MUTE << 8) | ch;
  277. setup->wIndex = (feature_id << 8) | audio_class->ctrl_intf;
  278. setup->wLength = 1;
  279. memcpy(g_audio_buf, &mute, 1);
  280. ret = usbh_control_transfer(audio_class->hport, setup, g_audio_buf);
  281. if (ret < 0) {
  282. return ret;
  283. }
  284. audio_class->as_msg_table[intf - audio_class->ctrl_intf - 1].mute = mute;
  285. return ret;
  286. }
  287. void usbh_audio_list_module(struct usbh_audio *audio_class)
  288. {
  289. USB_LOG_INFO("============= Audio module information ===================\r\n");
  290. USB_LOG_RAW("bcdADC :%04x\r\n", audio_class->bcdADC);
  291. USB_LOG_RAW("Num of audio stream :%u\r\n", audio_class->stream_intf_num);
  292. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  293. USB_LOG_RAW("\tstream name :%s\r\n", audio_class->as_msg_table[i].stream_name);
  294. USB_LOG_RAW("\tstream intf :%u\r\n", audio_class->as_msg_table[i].stream_intf);
  295. USB_LOG_RAW("\tNum of altsetting :%u\r\n", audio_class->as_msg_table[i].num_of_altsetting);
  296. for (uint8_t j = 0; j < audio_class->as_msg_table[i].num_of_altsetting; j++) {
  297. if (j == 0) {
  298. USB_LOG_RAW("\t\tIngore altsetting 0\r\n");
  299. continue;
  300. }
  301. USB_LOG_RAW("\t\tAltsetting :%u\r\n", j);
  302. USB_LOG_RAW("\t\t\tbNrChannels :%u\r\n", audio_class->as_msg_table[i].as_format[j].bNrChannels);
  303. USB_LOG_RAW("\t\t\tbBitResolution :%u\r\n", audio_class->as_msg_table[i].as_format[j].bBitResolution);
  304. USB_LOG_RAW("\t\t\tbSamFreqType :%u\r\n", audio_class->as_msg_table[i].as_format[j].bSamFreqType);
  305. for (uint8_t k = 0; k < audio_class->as_msg_table[i].as_format[j].bSamFreqType; k++) {
  306. uint32_t freq = 0;
  307. memcpy(&freq, &audio_class->as_msg_table[i].as_format[j].tSamFreq[3 * k], 3);
  308. USB_LOG_RAW("\t\t\t\tSampleFreq :%u\r\n", freq);
  309. }
  310. }
  311. }
  312. USB_LOG_INFO("============= Audio module information ===================\r\n");
  313. }
  314. static int usbh_audio_ctrl_connect(struct usbh_hubport *hport, uint8_t intf)
  315. {
  316. int ret;
  317. uint8_t cur_iface = 0;
  318. uint8_t cur_iface_count = 0;
  319. uint8_t cur_alt_setting = 0;
  320. uint8_t input_offset = 0;
  321. uint8_t output_offset = 0;
  322. uint8_t feature_unit_offset = 0;
  323. uint8_t *p;
  324. struct usbh_audio_ac_msg ac_msg_table[CONFIG_USBHOST_AUDIO_MAX_STREAMS];
  325. struct usbh_audio *audio_class = usbh_audio_class_alloc();
  326. if (audio_class == NULL) {
  327. USB_LOG_ERR("Fail to alloc audio_class\r\n");
  328. return -USB_ERR_NOMEM;
  329. }
  330. audio_class->hport = hport;
  331. audio_class->ctrl_intf = intf;
  332. hport->config.intf[intf].priv = audio_class;
  333. p = hport->raw_config_desc;
  334. while (p[DESC_bLength]) {
  335. switch (p[DESC_bDescriptorType]) {
  336. case USB_DESCRIPTOR_TYPE_INTERFACE_ASSOCIATION:
  337. cur_iface_count = p[3];
  338. break;
  339. case USB_DESCRIPTOR_TYPE_INTERFACE:
  340. cur_iface = p[INTF_DESC_bInterfaceNumber];
  341. cur_alt_setting = p[INTF_DESC_bAlternateSetting];
  342. break;
  343. case USB_DESCRIPTOR_TYPE_ENDPOINT:
  344. break;
  345. case AUDIO_INTERFACE_DESCRIPTOR_TYPE:
  346. if (cur_iface == audio_class->ctrl_intf) {
  347. switch (p[DESC_bDescriptorSubType]) {
  348. case AUDIO_CONTROL_HEADER: {
  349. struct audio_cs_if_ac_header_descriptor *desc = (struct audio_cs_if_ac_header_descriptor *)p;
  350. audio_class->bcdADC = desc->bcdADC;
  351. audio_class->bInCollection = desc->bInCollection;
  352. } break;
  353. case AUDIO_CONTROL_INPUT_TERMINAL: {
  354. struct audio_cs_if_ac_input_terminal_descriptor *desc = (struct audio_cs_if_ac_input_terminal_descriptor *)p;
  355. memcpy(&ac_msg_table[input_offset].ac_input, desc, sizeof(struct audio_cs_if_ac_input_terminal_descriptor));
  356. input_offset++;
  357. } break;
  358. case AUDIO_CONTROL_OUTPUT_TERMINAL: {
  359. struct audio_cs_if_ac_output_terminal_descriptor *desc = (struct audio_cs_if_ac_output_terminal_descriptor *)p;
  360. memcpy(&ac_msg_table[output_offset].ac_output, desc, sizeof(struct audio_cs_if_ac_output_terminal_descriptor));
  361. output_offset++;
  362. } break;
  363. case AUDIO_CONTROL_FEATURE_UNIT: {
  364. struct audio_cs_if_ac_feature_unit_descriptor *desc = (struct audio_cs_if_ac_feature_unit_descriptor *)p;
  365. memcpy(&ac_msg_table[feature_unit_offset].ac_feature_unit, desc, desc->bLength);
  366. feature_unit_offset++;
  367. } break;
  368. default:
  369. USB_LOG_ERR("Do not support %02x subtype\r\n", p[DESC_bDescriptorSubType]);
  370. return -USB_ERR_NOTSUPP;
  371. }
  372. } else if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
  373. switch (p[DESC_bDescriptorSubType]) {
  374. case AUDIO_STREAMING_GENERAL: {
  375. struct audio_cs_if_as_general_descriptor *desc = (struct audio_cs_if_as_general_descriptor *)p;
  376. /* all altsetting have the same general */
  377. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].stream_intf = cur_iface;
  378. memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_general, desc, sizeof(struct audio_cs_if_as_general_descriptor));
  379. } break;
  380. case AUDIO_STREAMING_FORMAT_TYPE: {
  381. struct audio_cs_if_as_format_type_descriptor *desc = (struct audio_cs_if_as_format_type_descriptor *)p;
  382. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].num_of_altsetting = (cur_alt_setting + 1);
  383. memcpy(&audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].as_format[cur_alt_setting], desc, desc->bLength);
  384. } break;
  385. default:
  386. break;
  387. }
  388. }
  389. break;
  390. case AUDIO_ENDPOINT_DESCRIPTOR_TYPE:
  391. if ((cur_iface > audio_class->ctrl_intf) && (cur_iface < (audio_class->ctrl_intf + cur_iface_count))) {
  392. if (p[DESC_bDescriptorSubType] == AUDIO_ENDPOINT_GENERAL) {
  393. struct audio_cs_ep_ep_general_descriptor *desc = (struct audio_cs_ep_ep_general_descriptor *)p;
  394. audio_class->as_msg_table[cur_iface - audio_class->ctrl_intf - 1].ep_attr = desc->bmAttributes;
  395. }
  396. }
  397. break;
  398. default:
  399. break;
  400. }
  401. /* skip to next descriptor */
  402. p += p[DESC_bLength];
  403. }
  404. if ((input_offset != output_offset) && (input_offset != feature_unit_offset)) {
  405. USB_LOG_ERR("Audio control descriptor is invalid\r\n");
  406. return -USB_ERR_INVAL;
  407. }
  408. if (cur_iface_count == 0xff) {
  409. USB_LOG_ERR("Audio descriptor must have iad descriptor\r\n");
  410. return -USB_ERR_INVAL;
  411. }
  412. audio_class->stream_intf_num = input_offset;
  413. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  414. /* Search 0x0101 in input or output desc */
  415. for (uint8_t streamidx = 0; streamidx < audio_class->stream_intf_num; streamidx++) {
  416. if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_input.bTerminalID) {
  417. /* INPUT --> FEATURE UNIT --> OUTPUT */
  418. audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[streamidx].ac_input.bTerminalID;
  419. /* Search input terminal id in feature desc */
  420. for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
  421. if (ac_msg_table[streamidx].ac_input.bTerminalID == ac_msg_table[featureidx].ac_feature_unit.bSourceID) {
  422. audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
  423. /* Search feature unit id in output desc */
  424. for (uint8_t outputid = 0; outputid < audio_class->stream_intf_num; outputid++) {
  425. if (ac_msg_table[featureidx].ac_feature_unit.bUnitID == ac_msg_table[outputid].ac_output.bSourceID) {
  426. audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[outputid].ac_output.bTerminalID;
  427. switch (ac_msg_table[outputid].ac_output.wTerminalType) {
  428. case AUDIO_OUTTERM_SPEAKER:
  429. audio_class->as_msg_table[i].stream_name = "speaker";
  430. break;
  431. case AUDIO_OUTTERM_HEADPHONES:
  432. audio_class->as_msg_table[i].stream_name = "headphoens";
  433. break;
  434. case AUDIO_OUTTERM_HEADDISPLAY:
  435. audio_class->as_msg_table[i].stream_name = "headdisplay";
  436. break;
  437. default:
  438. audio_class->as_msg_table[i].stream_name = "unknown";
  439. break;
  440. }
  441. break;
  442. }
  443. }
  444. break;
  445. }
  446. }
  447. } else if (audio_class->as_msg_table[i].as_general.bTerminalLink == ac_msg_table[streamidx].ac_output.bTerminalID) {
  448. /* OUTPUT --> FEATURE UNIT --> INPUT */
  449. audio_class->as_msg_table[i].output_terminal_id = ac_msg_table[streamidx].ac_output.bTerminalID;
  450. /* Search output terminal id in feature desc */
  451. for (uint8_t featureidx = 0; featureidx < audio_class->stream_intf_num; featureidx++) {
  452. if (ac_msg_table[streamidx].ac_output.bSourceID == ac_msg_table[featureidx].ac_feature_unit.bUnitID) {
  453. audio_class->as_msg_table[i].feature_terminal_id = ac_msg_table[featureidx].ac_feature_unit.bUnitID;
  454. /* Search feature unit id in input desc */
  455. for (uint8_t inputid = 0; inputid < audio_class->stream_intf_num; inputid++) {
  456. if (ac_msg_table[featureidx].ac_feature_unit.bSourceID == ac_msg_table[inputid].ac_input.bTerminalID) {
  457. audio_class->as_msg_table[i].input_terminal_id = ac_msg_table[inputid].ac_input.bTerminalID;
  458. switch (ac_msg_table[inputid].ac_input.wTerminalType) {
  459. case AUDIO_INTERM_MIC:
  460. audio_class->as_msg_table[i].stream_name = "mic";
  461. break;
  462. default:
  463. audio_class->as_msg_table[i].stream_name = "unknown";
  464. break;
  465. }
  466. break;
  467. }
  468. }
  469. break;
  470. }
  471. }
  472. }
  473. }
  474. }
  475. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  476. if (audio_class->as_msg_table[i].stream_name == NULL) {
  477. USB_LOG_ERR("Audio stream search fail\r\n");
  478. return -USB_ERR_NODEV;
  479. }
  480. }
  481. for (uint8_t i = 0; i < audio_class->stream_intf_num; i++) {
  482. ret = usbh_audio_close(audio_class, audio_class->as_msg_table[i].stream_name);
  483. if (ret < 0) {
  484. USB_LOG_ERR("Fail to close audio stream :%s\r\n", audio_class->as_msg_table[i].stream_name);
  485. return ret;
  486. }
  487. }
  488. usbh_audio_list_module(audio_class);
  489. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
  490. USB_LOG_INFO("Register Audio Class:%s\r\n", hport->config.intf[intf].devname);
  491. usbh_audio_run(audio_class);
  492. return 0;
  493. }
  494. static int usbh_audio_ctrl_disconnect(struct usbh_hubport *hport, uint8_t intf)
  495. {
  496. int ret = 0;
  497. struct usbh_audio *audio_class = (struct usbh_audio *)hport->config.intf[intf].priv;
  498. if (audio_class) {
  499. if (audio_class->isoin) {
  500. }
  501. if (audio_class->isoout) {
  502. }
  503. if (hport->config.intf[intf].devname[0] != '\0') {
  504. USB_LOG_INFO("Unregister Audio Class:%s\r\n", hport->config.intf[intf].devname);
  505. usbh_audio_stop(audio_class);
  506. }
  507. usbh_audio_class_free(audio_class);
  508. }
  509. return ret;
  510. }
  511. static int usbh_audio_data_connect(struct usbh_hubport *hport, uint8_t intf)
  512. {
  513. (void)hport;
  514. (void)intf;
  515. return 0;
  516. }
  517. static int usbh_audio_data_disconnect(struct usbh_hubport *hport, uint8_t intf)
  518. {
  519. (void)hport;
  520. (void)intf;
  521. return 0;
  522. }
  523. __WEAK void usbh_audio_run(struct usbh_audio *audio_class)
  524. {
  525. (void)audio_class;
  526. }
  527. __WEAK void usbh_audio_stop(struct usbh_audio *audio_class)
  528. {
  529. (void)audio_class;
  530. }
  531. const struct usbh_class_driver audio_ctrl_class_driver = {
  532. .driver_name = "audio_ctrl",
  533. .connect = usbh_audio_ctrl_connect,
  534. .disconnect = usbh_audio_ctrl_disconnect
  535. };
  536. const struct usbh_class_driver audio_streaming_class_driver = {
  537. .driver_name = "audio_streaming",
  538. .connect = usbh_audio_data_connect,
  539. .disconnect = usbh_audio_data_disconnect
  540. };
  541. CLASS_INFO_DEFINE const struct usbh_class_info audio_ctrl_intf_class_info = {
  542. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
  543. .bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
  544. .bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOCONTROL,
  545. .bInterfaceProtocol = 0x00,
  546. .id_table = NULL,
  547. .class_driver = &audio_ctrl_class_driver
  548. };
  549. CLASS_INFO_DEFINE const struct usbh_class_info audio_streaming_intf_class_info = {
  550. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS,
  551. .bInterfaceClass = USB_DEVICE_CLASS_AUDIO,
  552. .bInterfaceSubClass = AUDIO_SUBCLASS_AUDIOSTREAMING,
  553. .bInterfaceProtocol = 0x00,
  554. .id_table = NULL,
  555. .class_driver = &audio_streaming_class_driver
  556. };